Come dichiarare una variabile globale in React?


106

Ho inizializzato l' i18noggetto di traduzione una volta in un componente (primo componente che viene caricato nell'app). Lo stesso oggetto è richiesto in tutti gli altri componenti. Non voglio reinizializzarlo in ogni componente. Qual è il modo per aggirare? Renderlo disponibile per l'ambito della finestra non aiuta in quanto ho bisogno di usarlo nel render()metodo.

Si prega di suggerire una soluzione generica per questi problemi e non una soluzione specifica per i18n.


1
È possibile utilizzare Reduxo Fluxlibreria in grado di gestire i dati o dello stato a livello globale. e puoi passarlo facilmente attraverso tutti i tuoi componenti
vistajess

Qualsiasi altro modo ? Abbiamo avviato il progetto senza alcun React Framework perché era l'inizio di React. Ora il collegamento di ogni componente al negozio Redux richiederà uno sforzo enorme.
sapy

3
Qualcosa come React-Global funzionerebbe per te?
TwoStraws

Risposte:


50

Perché non provi a usare Context ?

È possibile dichiarare una variabile di contesto globale in uno qualsiasi dei componenti padre e questa variabile sarà accessibile attraverso l'albero dei componenti da this.context.varname. Devi solo specificare childContextTypese getChildContextnel componente genitore e successivamente puoi usarlo / modificarlo da qualsiasi componente semplicemente specificandolo contextTypesnel componente figlio.

Tuttavia, prendi nota di questo come indicato nei documenti:

Proprio come è meglio evitare le variabili globali quando si scrive codice chiaro, nella maggior parte dei casi dovresti evitare di usare il contesto. In particolare, pensaci due volte prima di usarlo per "salvare la digitazione" e usarlo invece di passare oggetti di scena espliciti.


30
vicino . ma Tutti i componenti non hanno una relazione padre figlio e Context non funziona oltre quell'albero. Voglio i18n attraverso l'applicazione.
sapy

@sapy questo è il motivo per cui si dovrebbe usare i18n come stato Redux non come una variabile di contesto vedere la mia risposta qui: stackoverflow.com/questions/33413880/...
Fareed Alnamrouti

9
Risposta orribile.
r3wt

Da parte mia, consiglierei invece di usare redux, specialmente per le grandi app
Hosny Ben

37

Beyond React

Potresti non essere a conoscenza del fatto che un'importazione è già globale . Se si esporta un oggetto (singleton) è quindi accessibile globalmente come un'istruzione di importazione e può anche essere modificato globalmente .

Se vuoi inizializzare qualcosa a livello globale ma assicurarti che sia modificato solo una volta, puoi usare questo approccio singleton che inizialmente ha proprietà modificabili ma poi puoi usarlo Object.freezedopo il suo primo utilizzo per assicurarti che sia immutabile nel tuo scenario init.

const myInitObject = {}
export default myInitObject

quindi nel tuo metodo init referenziandolo:

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

La myInitObjectsaranno ancora globale in quanto si può fare riferimento ovunque come importazione , ma rimarrà congelato e buttare se qualcuno tenta di modificarlo.

Se si utilizza react-create-app

(cosa stavo cercando in realtà) In questo scenario puoi anche inizializzare gli oggetti globali in modo pulito quando fai riferimento alle variabili di ambiente.

La creazione di un file .env alla radice del progetto con REACT_APP_variabili prefissate all'interno funziona abbastanza bene. Puoi fare riferimento all'interno del tuo JS e JSX di process.env.REACT_APP_SOME_VARcui hai bisogno ED è immutabile per design.

Ciò evita di dover impostare window.myVar = %REACT_APP_MY_VAR%in HTML.

Vedi dettagli più utili su questo direttamente da Facebook:

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


6
Questo è onestamente un ottimo suggerimento, ho avuto problemi con i miei token di autenticazione poiché utilizzo il rendering lato server. Ho finito per caricare da localstorage al primo caricamento e quindi memorizzarlo in un file di configurazione separato che posso semplicemente importare. Bella risposta.
otto

1
Questa è la migliore risposta finora!
thiloilg

33

Non è raccomandato ma ... puoi usare componentWillMount dalla tua classe app per aggiungere le tue variabili globali attraverso di essa ... un po 'così:

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

considera ancora questo un trucco ... ma porterà a termine il tuo lavoro

btw componentWillMount viene eseguito una volta prima del rendering, vedere di più qui: https://reactjs.org/docs/react-component.html#mounting-componentwillmount


1
È un trucco per alcuni casi d'uso. Sto integrando un'app React nel contesto di un'altra app non React nella mia azienda. Questo sembra un ottimo modo per esporre metodi pubblici per l'app che consuma. Ho sbagliato? C'è un modo migliore?
mccambridge

2
Inoltre, tieni presente che componentWillMountè stato deprecato: reactjs.org/blog/2018/03/27/update-on-async-rendering.html
RyanNerd

@mccambridge So che è tardi ma invierei una funzione dall'app non React in React che chiameresti per inviare le informazioni. A proposito, puoi farlo con iframe.
Nic Szerman

6

Crea un file denominato "config.js" nella cartella ./src con questo contenuto:

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

Nel tuo file principale "index.js" inserisci questa riga:

import './config';

Ovunque tu abbia bisogno del tuo oggetto usa questo:

global.config.i18n.welcome.en

5

Può mantenere le variabili globali nel webpack cioè in webpack.config.js

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

Nel modulo js può leggere come

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

Spero che questo ti aiuti.



2

7
Nota: se stai utilizzando la sintassi ES6 (che ora è consigliata) o componenti puri, i mixin non sono disponibili. Il consiglio è di comporre i tuoi componenti. medium.com/@dan_abramov/…
Aren

1
questa sembra una buona idea in quanto puoi centralizzare la logica e successivamente passare a Flux altri tipi di archiviazione (ad es. Localstorage o DB lato client)
dcsan

2
Questa risposta avrebbe dovuto essere espansa per includere un esempio di codice. I collegamenti possono interrompersi.
vapcguy

0

Ecco un approccio moderno, utilizzando globalThis, che abbiamo adottato per la nostra app React Native .

globalThis è ora incluso 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 (il nostro file del punto di ingresso principale )

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

Non so cosa stiano cercando di dire con questa roba "React Context" - mi parlano in greco, ma ecco come l'ho fatto:

Trasportare valori tra le funzioni, sulla stessa pagina

Nel tuo costruttore, collega il tuo setter:

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

Quindi dichiara una funzione appena sotto il tuo costruttore:

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

Quando vuoi impostarlo, chiama this.setSomeVariable("some value");

(Potresti anche essere in grado di farla franca this.state.myProperty = "some value";)

Quando vuoi ottenerlo, chiama var myProp = this.state.myProperty;

L'utilizzo alert(myProp);dovrebbe darti some value.

Metodo di scaffolding aggiuntivo per trasferire i valori tra pagine / componenti

Puoi assegnare un modello a this(tecnicamente this.stores), quindi puoi fare riferimento ad esso con 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

Salvalo in una cartella chiamata storescome yourForm.jsx.

Quindi puoi farlo in un'altra pagina:

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

Se avessi impostato this.state.someGlobalVariablein un altro componente utilizzando una funzione come:

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

che leghi nel costruttore con:

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

il valore in propertyTextToAddsarebbe visualizzato SomePageutilizzando il codice mostrato sopra.


3
Scusa per essere nuovo qui, ma ho appena imparato React e non sono sicuro del motivo per cui questa risposta ottiene così tanti downvoted
qualcuno senza utilità il

3
@someoneuseless Esattamente! Ed è per questo che mi rifiuto di cancellarlo e mi inchino alle masse. Solo perché vogliono usare "Context" (qualunque cosa sia) e questi altri oggetti divertenti non significa che tutti debbano farlo. Dammi il cinque!
vapcguy
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.