Как объявить глобальную переменную в React?

110

Я инициализировал i18nобъект перевода один раз в компоненте (первый компонент, загружаемый в приложение). Этот же объект требуется во всех других компонентах. Я не хочу повторно инициализировать его в каждом компоненте. Что вокруг? Сделать его доступным для оконной области не помогает, так как мне нужно использовать его в render()методе.

Предложите общее решение этой проблемы, а не конкретное решение i18n.

сапи
источник
1
Вы можете использовать Reduxили Fluxбиблиотеку, которая может обрабатывать данные или состояние глобально. и вы можете легко передать его через все ваши компоненты
vistajess
Любым другим путем ? Мы начали проект без какой-либо React Framework, потому что React только зарождался. Теперь подключение каждого компонента к хранилищу Redux потребует огромных усилий.
sapy
3
Что-то вроде react-global работает для вас?
TwoStraws

Ответы:

51

Почему бы вам не попробовать использовать контекст ?

Вы можете объявить глобальную переменную контекста в любом из родительских компонентов, и эта переменная будет доступна в дереве компонентов с помощью this.context.varname . Вам нужно только указать childContextTypesи getChildContextв родительском компоненте, и после этого вы можете использовать / изменять это из любого компонента, просто указав contextTypesв дочернем компоненте.

Однако обратите внимание на это, как указано в документации:

Так же, как при написании понятного кода лучше избегать использования глобальных переменных, в большинстве случаев вам следует избегать использования контекста. В частности, дважды подумайте, прежде чем использовать его для «экономии ввода» и использования его вместо явной передачи свойств.

Найшил Вердан
источник
30
близко . но у всех компонентов нет родительских и дочерних отношений, и контекст не работает за пределами этого дерева. Я хочу использовать i18n в приложении.
Сапи
@sapy, вот почему вы должны использовать i18n как состояние redux, а не как переменную контекста, см. мой ответ здесь: stackoverflow.com/questions/33413880/…
Fareed Alnamrouti
9
Ужасный ответ.
r3wt
Со своей стороны, я бы рекомендовал вместо этого использовать redux, особенно для больших приложений
Хосни Бен
38

За пределами React

Возможно, вы не знали, что импорт уже является глобальным . Если вы экспортируете объект (синглтон), он становится глобально доступным как оператор импорта, а также может быть изменен глобально .

Если вы хотите инициализировать что-то глобально, но убедитесь, что оно изменено только один раз, вы можете использовать этот одноэлементный подход, который изначально имеет изменяемые свойства, но затем вы можете использовать Object.freezeего после первого использования, чтобы гарантировать его неизменность в сценарии инициализации.

const myInitObject = {}
export default myInitObject

затем в вашем методе инициализации, ссылаясь на него:

import myInitObject from './myInitObject'
myInitObject.someProp = 'i am about to get cold'
Object.freeze(myInitObject)

Он по- myInitObjectпрежнему будет глобальным, поскольку на него можно ссылаться где угодно как на импорт но он останется замороженным и выбрасывается, если кто-то попытается его изменить.

При использовании response-create-app

(на самом деле то, что я искал) В этом сценарии вы также можете чисто инициализировать глобальные объекты при обращении к переменным среды.

Создание файла .env в корне вашего проекта с префиксными REACT_APP_переменными внутри вполне подойдет. Вы можете ссылаться в своих JS и JSX по process.env.REACT_APP_SOME_VARмере необходимости, И они неизменны по дизайну.

Это позволяет избежать установки window.myVar = %REACT_APP_MY_VAR%в HTML.

Смотрите более полезные подробности об этом напрямую в Facebook:

https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables

Джейсон Себринг
источник
6
Честно говоря, это отличный совет, у меня были проблемы с моими токенами аутентификации, так как я использую рендеринг на стороне сервера. В итоге я загрузился из localstorage при первой загрузке, а затем сохранил его в отдельном файле конфигурации, который я могу просто импортировать. Отличный ответ.
Восемь
1
На данный момент это лучший ответ!
thiloilg
33

Не рекомендуется, но .... вы можете использовать componentWillMount из своего класса приложения, чтобы добавить через него свои глобальные переменные ... примерно так:

componentWillMount: function () {
    window.MyVars = {
        ajax: require('../helpers/ajax.jsx'),
        utils: require('../helpers/utils.jsx')
    };
}

все еще считайте это взломом ... но он выполнит вашу работу

btw componentWillMount выполняется один раз перед рендерингом, подробнее см. здесь: https://reactjs.org/docs/react-component.html#mounting-componentwillmount

потрясенный
источник
1
Это хитрость для определенных случаев использования. Я интегрирую приложение React в контекст другого приложения, отличного от React, в моей компании. Кажется, это отличный способ раскрыть общедоступные методы для приложения-потребителя. Я ошибся? Есть ли способ лучше?
mccambridge
2
Также имейте в виду, что componentWillMountэто устарело: reactjs.org/blog/2018/03/27/update-on-async-rendering.html
RyanNerd
@mccambridge Я знаю, что это поздно, но я бы отправил функцию из приложения, отличного от React, в React, которую вы должны были бы вызвать для отправки информации. Кстати, вы можете сделать это с помощью iframe.
Nic Szerman
8

Создайте файл с именем "config.js" в папке ./src со следующим содержимым:

module.exports = global.config = {
    i18n: {
        welcome: {
            en: "Welcome",
            fa: "خوش آمدید"
        }
        // rest of your translation object
    }
    // other global config variables you wish
};

В главном файле index.js поместите эту строку:

import './config';

Везде, где вам нужен ваш объект, используйте это:

global.config.i18n.welcome.en
Алиреза
источник
5

Может хранить глобальные переменные в webpack, т.е. в webpack.config.js

externals: {
  'config': JSON.stringify(GLOBAL_VARIABLE: "global var value")
}

В модуле js можно читать как

var config = require('config')
var GLOBAL_VARIABLE = config.GLOBAL_VARIABLE

Надеюсь, это поможет.

Шашанк Бхонг
источник
2

Вы можете использовать миксины в реакции https://facebook.github.io/react/docs/reusable-components.html#mixins .

Рамратан Гупта
источник
7
Примечание. Если вы используете синтаксис ES6 (который сейчас рекомендуется) или чистые компоненты, миксины недоступны. Рекомендуется составить ваши компоненты. medium.com/@dan_abramov/…
Aren
1
это кажется хорошей идеей, так как тогда вы можете централизовать свою логику, а затем перейти к другим типам хранилищ Flux (например, Localstorage или БД на стороне клиента)
dcsan
2
Этот ответ следовало расширить, включив в него образец кода. Ссылки могут порваться.
vapcguy
0

Вот современный подход, который globalThisмы использовали для нашего приложения React Native .

globalThis теперь входит в ...


appGlobals.ts

// define our parent property accessible via globalThis. Also apply the TypeScript type.
var app: globalAppVariables;

// define the child properties and their types. 
type globalAppVariables = {
  messageLimit: number;
  // more can go here. 
};

// set the values.
globalThis.app = {
  messageLimit: 10,
  // more can go here.
};


// Freeze so these can only be defined in this file.
Object.freeze(globalThis.app);


App.tsx ( наш основной файл точки входа )

import './appGlobals'

// other code


anyWhereElseInTheApp.tsx

const chatGroupQuery = useQuery(GET_CHAT_GROUP_WITH_MESSAGES_BY_ID, {
  variables: {
    chatGroupId,
    currentUserId: me.id,
    messageLimit: globalThis.app.messageLimit, // 👈 used here.
  },
});
GollyJer
источник
-6

Я не знаю, что они пытаются сказать этим "React Context" - они говорят со мной по-гречески, но вот как я это сделал:

Передача значений между функциями на одной странице

В своем конструкторе привяжите свой сеттер:

this.setSomeVariable = this.setSomeVariable.bind(this);

Затем объявите функцию чуть ниже вашего конструктора:

setSomeVariable(propertyTextToAdd) {
    this.setState({
        myProperty: propertyTextToAdd
    });
}

Когда вы захотите установить его, позвоните this.setSomeVariable("some value");

(Возможно, вам даже удастся уйти this.state.myProperty = "some value";)

Когда захочешь получить, звони var myProp = this.state.myProperty;

Использование alert(myProp);должно дать вам some value.

Дополнительный метод построения лесов для переноса значений по страницам / компонентам

Вы можете назначить модель this(технически this.stores), чтобы затем ссылаться на нее this.state:

import Reflux from 'reflux'
import Actions from '~/actions/actions`

class YourForm extends Reflux.Store
{
    constructor()
    {
        super();
        this.state = {
            someGlobalVariable: '',
        };
        this.listenables = Actions;
        this.baseState = {
            someGlobalVariable: '',
        };
    }

    onUpdateFields(name, value) {
        this.setState({
            [name]: value,
        });
    }

    onResetFields() {
        this.setState({
           someGlobalVariable: '',
        });
    }
}
const reqformdata = new YourForm

export default reqformdata

Сохраните это в папке под storesназваниемyourForm.jsx .

Затем вы можете сделать это на другой странице:

import React from 'react'
import Reflux from 'reflux'
import {Form} from 'reactstrap'
import YourForm from '~/stores/yourForm.jsx'

Reflux.defineReact(React)

class SomePage extends Reflux.Component {
    constructor(props) {
        super(props);
        this.state = {
            someLocalVariable: '',
        }
        this.stores = [
            YourForm,
        ]
    }
    render() {

        const myVar = this.state.someGlobalVariable;
        return (
            <Form>
                <div>{myVar}</div>
            </Form>
        )
    }
}
export default SomePage

Если вы установили this.state.someGlobalVariableдругой компонент, используя такую ​​функцию, как:

setSomeVariable(propertyTextToAdd) {
    this.setState({
       myGlobalVariable: propertyTextToAdd
   });
}

которые вы связываете в конструкторе с помощью:

this.setSomeVariable = this.setSomeVariable.bind(this);

значение propertyTextToAddбудет отображаться при SomePageиспользовании кода, показанного выше.

vapcguy
источник
3
Извините за то, что был здесь новичком, но я только изучаю React и не понимаю, почему этот ответ получил так много голосов против
somethinguseless
3
@someoneuseless Совершенно верно! И поэтому я отказываюсь удалять его и поклоняюсь массам. То, что они хотят использовать «Контекст» (что бы это ни было) и эти другие забавные объекты, не означает, что всем это нужно. Дай пять!
vapcguy