Wie deklariere ich eine globale Variable in React?

106

Ich habe das i18nÜbersetzungsobjekt einmal in einer Komponente initialisiert (erste Komponente, die in der App geladen wird). In allen anderen Komponenten ist dasselbe Objekt erforderlich. Ich möchte es nicht in jeder Komponente neu initialisieren. Wie ist der Weg herum? Es hilft nicht, es für den Fensterbereich verfügbar zu machen, da ich es in der render()Methode verwenden muss.

Bitte schlagen Sie eine generische Lösung für dieses Problem vor und keine i18n-spezifische Lösung.

sapy
quelle
1
Sie können mit Reduxoder FluxBibliothek , die weltweit Daten oder Zustand verarbeiten kann. und Sie können es leicht durch alle Ihre Komponenten führen
vistajess
Irgendein anderer Weg? Wir haben das Projekt ohne React Framework gestartet, da es am frühen Tag von React war. Das Verbinden jeder Komponente mit dem Redux Store erfordert jetzt einen enormen Aufwand.
Sapy
3
Möchten Sie so etwas wie eine globale Reaktion für Sie?
TwoStraws

Antworten:

50

Warum versuchen Sie nicht, Context zu verwenden ? ?

Sie können eine globale Kontextvariable in jeder der übergeordneten Komponenten deklarieren. Auf diese Variable kann im gesamten Komponentenbaum zugegriffen werden this.context.varname. Sie müssen nur childContextTypesund getChildContextin der übergeordneten Komponente angeben und danach können Sie diese von jeder Komponente aus verwenden / ändern, indem Sie nur angebencontextTypes .

Beachten Sie dies jedoch wie in den Dokumenten erwähnt:

So wie globale Variablen beim Schreiben von klarem Code am besten vermieden werden, sollten Sie in den meisten Fällen die Verwendung von Kontext vermeiden. Überlegen Sie insbesondere zweimal, bevor Sie es verwenden, um "das Tippen zu speichern" und es zu verwenden, anstatt explizite Requisiten zu übergeben.

Naisheel Verdhan
quelle
30
schließen . Alle Komponenten haben jedoch keine übergeordnete untergeordnete Beziehung, und der Kontext funktioniert nicht über diesen Baum hinaus. Ich möchte i18n in der gesamten Anwendung.
Sapy
@sapy aus diesem Grund sollten Sie i18n als Redux-Status und nicht als Kontextvariable verwenden. Siehe meine Antwort hier: stackoverflow.com/questions/33413880/…
Fareed Alnamrouti
9
Schreckliche Antwort.
r3wt
Von meiner Seite würde ich empfehlen, stattdessen Redux zu verwenden, und speziell für große Apps
Hosny Ben
37

Jenseits der Reaktion

Möglicherweise wissen Sie nicht, dass ein Import bereits global ist . Wenn Sie ein Objekt (Singleton) exportieren, ist es als Importanweisung global zugänglich und kann auch global geändert werden .

Wenn Sie etwas global initialisieren möchten, aber sicherstellen möchten, dass es nur einmal geändert wird, können Sie diesen Singleton-Ansatz verwenden , der anfänglich veränderbare Eigenschaften aufweist. Sie können ihn jedoch Object.freezenach seiner ersten Verwendung verwenden, um sicherzustellen, dass er in Ihrem Init-Szenario unveränderlich ist .

const myInitObject = {}
export default myInitObject

dann in Ihrer init-Methode, die darauf verweist:

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

Das myInitObjectwird weiterhin global sein, da es überall als Import referenziert werden kann aber eingefroren bleibt und geworfen wird, wenn jemand versucht, es zu ändern.

Bei Verwendung der React-Create-App

(wonach ich eigentlich gesucht habe) In diesem Szenario können Sie globale Objekte auch sauber referenzieren, wenn Sie auf Umgebungsvariablen verweisen.

Das Erstellen einer .env- Datei im Stammverzeichnis Ihres Projekts mit darin enthaltenen PräfixvariablenREACT_APP_ funktioniert sehr gut. Sie können innerhalb Ihres JS und JSX process.env.REACT_APP_SOME_VARnach Bedarf referenzieren UND es ist von Natur aus unveränderlich.

Dadurch muss nicht window.myVar = %REACT_APP_MY_VAR%in HTML festgelegt werden.

Weitere nützliche Details dazu finden Sie direkt auf Facebook:

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

Jason Sebring
quelle
6
Dies ist ehrlich gesagt ein großartiger Tipp. Ich hatte Probleme mit meinen Authentifizierungstoken, da ich Server Side Rendering verwende. Beim ersten Laden wurde ich von localstorage geladen und dann in einer separaten Konfigurationsdatei gespeichert, die ich einfach importieren kann. Gute Antwort.
Acht
1
Dies ist die bisher beste Antwort!
Thiloilg
33

Wird nicht empfohlen, aber ... Sie können componentWillMount aus Ihrer App-Klasse verwenden, um Ihre globalen Variablen hinzuzufügen ... ein bisschen wie folgt:

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

Betrachten Sie dies immer noch als Hack ... aber es wird Ihre Arbeit erledigen

Übrigens: componentWillMount wird vor dem Rendern einmal ausgeführt. Weitere Informationen finden Sie hier: https://reactjs.org/docs/react-component.html#mounting-componentwillmount

rokyed
quelle
1
Es ist ein Hack für bestimmte Anwendungsfälle. Ich integriere eine React-App in den Kontext einer anderen Nicht-React-App in meinem Unternehmen. Dies scheint eine großartige Möglichkeit zu sein, öffentliche Methoden für die konsumierende App verfügbar zu machen. Liege ich falsch? Gibt es einen besseren Weg?
McCambridge
2
BeachtencomponentWillMount
Sie
@mccambridge Ich weiß, dass dies zu spät ist, aber ich würde eine Funktion aus der Nicht-React-App an React senden, die Sie aufrufen würden, um die Informationen zu senden. Übrigens können Sie dies mit Iframes tun.
Nic Szerman
6

Erstellen Sie eine Datei mit dem Namen "config.js" im Ordner ./src mit folgendem Inhalt:

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

Fügen Sie in Ihre Hauptdatei "index.js" diese Zeile ein:

import './config';

Überall dort, wo Sie Ihr Objekt benötigen, verwenden Sie Folgendes:

global.config.i18n.welcome.en
Alireza
quelle
5

Kann globale Variablen im Webpack behalten, dh in webpack.config.js

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

In js Modul kann man gerne lesen

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

Hoffe das wird helfen.

Shashank Bhong
quelle
2

Sie können Mixins in Reaktion https://facebook.github.io/react/docs/reusable-components.html#mixins verwenden .

Ramratan Gupta
quelle
7
Hinweis: Wenn Sie die ES6-Syntax (die jetzt empfohlen wird) oder reine Komponenten verwenden, sind keine Mixins verfügbar. Es wird empfohlen, Ihre Komponenten zusammenzustellen. medium.com/@dan_abramov/…
Aren
1
Dies scheint eine gute Idee zu sein, da Sie dann Ihre Logik zentralisieren und später andere Flux-Speichertypen (z. B. Localstorage oder clientseitige
Datenbank
2
Diese Antwort sollte um ein Codebeispiel erweitert worden sein. Links können brechen.
vapcguy
0

Hier ist ein moderner Ansatz, den globalThiswir für unsere React Native- App verwendet haben.

globalThis ist jetzt enthalten in ...


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 ( unsere Haupteinstiegspunktdatei )

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
quelle
-6

Ich weiß nicht, was sie mit diesem "React Context" -Stoff sagen wollen - sie sprechen mit mir Griechisch, aber so habe ich es gemacht:

Übertragen von Werten zwischen Funktionen auf derselben Seite

Binden Sie in Ihrem Konstruktor Ihren Setter:

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

Deklarieren Sie dann eine Funktion direkt unter Ihrem Konstruktor:

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

Wenn Sie es einstellen möchten, rufen Sie an this.setSomeVariable("some value");

(Vielleicht können Sie sogar damit durchkommen this.state.myProperty = "some value"; )

Wenn Sie es bekommen möchten, rufen Sie an var myProp = this.state.myProperty;

Verwenden alert(myProp);sollte Ihnen geben some value.

Zusätzliche Gerüstmethode zum Übertragen von Werten über Seiten / Komponenten hinweg

Sie können this(technisch this.stores) ein Modell zuweisen , um es dann zu referenzieren 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

Speichern Sie diese in einen Ordner namens storesalsyourForm.jsx .

Dann können Sie dies auf einer anderen Seite tun:

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

Wenn Sie eine this.state.someGlobalVariableandere Komponente mit einer Funktion wie der folgenden eingestellt haben:

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

dass Sie im Konstruktor binden mit:

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

Der Wert in propertyTextToAddwird SomePagemit dem oben gezeigten Code angezeigt.

vapcguy
quelle
3
Es tut
mir
3
@someoneuseless Genau! Und deshalb weigere ich mich, es zu löschen und mich den Massen zuzuwenden. Nur weil sie "Context" (was auch immer das ist) und diese anderen lustigen Objekte verwenden wollen, heißt das nicht, dass jeder das muss. Gib mir fünf!
vapcguy