Як оголосити глобальну змінну в React?


106

Я ініціалізував i18nоб’єкт перекладу один раз у компоненті (перший компонент, який завантажується у програмі). Цей же об'єкт потрібен у всіх інших компонентах. Я не хочу повторно ініціалізувати його у всіх компонентах. Який шлях? Надання його доступності для області вікон не допомагає, оскільки мені потрібно використовувати його в render()методі.

Будь ласка, запропонуйте загальне рішення для цієї проблеми, а не конкретне i18n рішення.


1
Ви можете використовувати Reduxабо Fluxбібліотеку, яка може обробляти дані або стан у всьому світі. і ви зможете легко пройти через усі його компоненти
vistajess

Іншим способом? Ми розпочали проект без будь-якої програми React Framework, тому що це було раннього дня React. Тепер підключення кожного компонента до магазину Redux вимагатиме величезних зусиль.
сапі

3
Чи буде щось на кшталт реакційно-глобальної роботи для вас?
TwoStraws

Відповіді:


50

Чому б не спробувати використовувати Context ?

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

Однак, зверніть увагу на це, як зазначено в документах:

Так само, як глобальних змінних найкраще уникати під час написання чіткого коду, у більшості випадків слід уникати використання контексту. Зокрема, подумайте двічі, перш ніж використовувати його для "збереження набору тексту" та використання його замість передачі явного реквізиту.


30
закрити. але всі компоненти не мають батьківських дочірніх відносин, і контекст не працює далі цього дерева. Я хочу i18n в додатку.
сапі

@sapy саме тому ви повинні використовувати i18n як стан Redux НЕ в якості змінної контексту побачити моя відповідь тут: stackoverflow.com/questions/33413880 / ...
Фаріда Alnamrouti

9
Жахлива відповідь.
r3wt

З мого боку, я б рекомендував використовувати замість них редукс, і спеціально для великих додатків
Hosny Ben

37

Поза Реакцією

Можливо, ви не знаєте, що імпорт вже є глобальним . Якщо ви експортуєте об'єкт (синглтон), він буде глобально доступний як імпорт, і він також може бути модифікований глобально .

Якщо ви хочете ініціалізувати щось у всьому світі, але забезпечити його лише модифікований один раз, ви можете скористатися цим синглтонним підходом, який спочатку має властивості, що змінюються, але потім ви можете використовувати Object.freezeйого після першого використання, щоб забезпечити його незмінність у вашому сценарії init.

const myInitObject = {}
export default myInitObject

то у вашому методі init, що посилається на нього:

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

Це myInitObjectвсе ще буде глобальним, оскільки його можна десь посилати як імпорт, але він залишатиметься замороженим і кинутим, якщо хтось спробує його змінити.

Якщо ви використовуєте react-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, а потім зберігав його в окремому файлі Config, який я можу просто імпортувати. Чудова відповідь.
Вісім

1
Це найкраща відповідь поки!
тілоїг

33

Не рекомендується, але .... ви можете використовувати компонентWillMount з класу додатків, щоб додати свої глобальні змінні через нього ... трохи так:

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 в контекст іншого нереактивного додатку в моїй компанії. Це здається чудовим способом розкрити загальнодоступні методи для споживчого додатка. Я помиляюся? Чи є кращий спосіб?
mccambridge

2
Також майте на увазі, componentWillMountщо застаріло: reactjs.org/blog/2018/03/27/update-on-async-rendering.html
RyanNerd

@mccambridge Я знаю, що це пізно, але я б надіслав у React функцію з додатка, що не реагує, який би ти зателефонував, щоб надіслати інформацію. До речі, це можна зробити за допомогою iframes.
Nic Szerman

6

Створіть файл із назвою "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/…
Арен

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.
  },
});

-6

Я не знаю, що вони намагаються сказати з цим матеріалом "Реагувати контекст" - вони говорять мені грецькою мовою, але ось як я це зробив:

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

У конструкторі зв’яжіть свій сетер:

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допомогою коду, показаного вище.


3
Вибачте за те, що тут я є новим, але я просто дізнаюся, що реагую, і не впевнений, чому ця відповідь не сприймає стільки людей
хтось безкорисний

3
@someoneuseless Рівно! І саме тому я відмовляюсь видалити його і скинути маси. Тільки тому, що вони хочуть використовувати "Контекст" (що б там не було), а ці інші смішні об'єкти не означає, що всім потрібно. Дай п'ять!
vapcguy
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.