¿Cómo declarar una variable global en React?


106

Inicialicé el i18nobjeto de traducción una vez en un componente (primer componente que se carga en la aplicación). Ese mismo objeto se requiere en todos los demás componentes. No quiero reinicializarlo en todos los componentes. ¿Qué hay alrededor? Ponerlo a disposición del alcance de la ventana no ayuda, ya que necesito usarlo en el render()método.

Sugiera una solución genérica para estos problemas y no una solución específica de i18n.


1
Se puede utilizar Reduxo Fluxbiblioteca que puede manejar datos o estado a nivel mundial. y puede pasarlo fácilmente a través de todos sus componentes
vistajess

Cualquier otra forma ? Comenzamos el proyecto sin ningún React Framework porque eran los primeros días de React. Ahora, conectar todos los componentes a la tienda Redux requerirá un gran esfuerzo.
sapy

3
¿Le funcionaría algo como react-global ?
TwoStraws

Respuestas:


50

¿Por qué no intentas usar Context? ?

Puede declarar una variable de contexto global en cualquiera de los componentes principales y esta variable será accesible a través del árbol de componentes por this.context.varname. Solo tiene que especificar childContextTypesy getChildContexten el componente principal y, a partir de entonces, puede usar / modificar esto desde cualquier componente simplemente especificando contextTypesen el componente secundario.

Sin embargo, tome nota de esto como se menciona en los documentos:

Así como es mejor evitar las variables globales al escribir código claro, debe evitar el uso de contexto en la mayoría de los casos. En particular, piénselo dos veces antes de usarlo para "guardar la escritura" y usarlo en lugar de pasar apoyos explícitos.


30
cerca . pero Todos los componentes no tienen una relación entre padres e hijos y el contexto no funciona más allá de ese árbol. Quiero i18n en toda la aplicación.
sapy

@sapy, esta es la razón por la que debe usar i18n como estado redux, no como una variable de contexto, vea mi respuesta aquí: stackoverflow.com/questions/33413880/…
Fareed Alnamrouti

9
Respuesta horrible.
r3wt

Por mi parte, recomendaría usar redux en su lugar, y especialmente para aplicaciones grandes
Hosny Ben

37

Más allá de React

Es posible que no sepa que una importación ya es global . Si exporta un objeto (singleton), será accesible globalmente como una declaración de importación y también se puede modificar globalmente .

Si desea inicializar algo globalmente pero asegurarse de que solo se modifique una vez, puede usar este enfoque singleton que inicialmente tiene propiedades modificables, pero luego puede usarlo Object.freezedespués de su primer uso para asegurarse de que sea inmutable en su escenario de inicio.

const myInitObject = {}
export default myInitObject

luego en su método init haciendo referencia a él:

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

El myInitObjecttodavía será global, ya que puede ser referenciado en cualquier lugar como una importación pero se mantendrá congelada y tirar si los intentos que cualquiera pueda modificarlo.

Si usa react-create-app

(lo que estaba buscando en realidad) En este escenario, también puede inicializar objetos globales limpiamente al hacer referencia a variables de entorno.

La creación de un archivo .env en la raíz de su proyecto con REACT_APP_variables prefijadas en el interior funciona bastante bien. Puede hacer referencia dentro de su JS y JSX process.env.REACT_APP_SOME_VARsegún lo necesite Y es inmutable por diseño.

Esto evita tener que configurar window.myVar = %REACT_APP_MY_VAR%en HTML.

Vea más detalles útiles sobre esto directamente desde Facebook:

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


6
Honestamente, este es un gran consejo, estaba teniendo problemas con mis tokens de autenticación ya que estoy usando Server Side Rendering. Terminé cargando desde localstorage en la primera carga y luego guardándolo en un archivo de configuración separado que puedo importar. Gran respuesta.
8 de

1
¡Esta es la mejor respuesta hasta ahora!
thiloilg

33

No se recomienda, pero ... puedes usar componentWillMount de tu clase de aplicación para agregar tus variables globales a través de ella ... un poco así:

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

aún considero esto un truco ... pero hará tu trabajo

Por cierto, componentWillMount se ejecuta una vez antes de renderizar, vea más aquí: https://reactjs.org/docs/react-component.html#mounting-componentwillmount


1
Es un truco para ciertos casos de uso. Estoy integrando una aplicación React en el contexto de otra aplicación que no es React en mi empresa. Esta parece una excelente manera de exponer métodos públicos para la aplicación consumidora. ¿Me equivoco? ¿Existe una forma mejor?
mccambridge

2
También tenga en cuenta que componentWillMountestá en desuso: reactjs.org/blog/2018/03/27/update-on-async-rendering.html
RyanNerd

@mccambridge Sé que es tarde, pero enviaría una función desde la aplicación que no es React a React a la que llamarías para enviar la información. Por cierto, puedes hacer esto con iframes.
Nic Szerman

6

Cree un archivo llamado "config.js" en la carpeta ./src con este contenido:

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

En su archivo principal "index.js" ponga esta línea:

import './config';

Donde sea que necesite su objeto use esto:

global.config.i18n.welcome.en

5

Puede mantener variables globales en el paquete web, es decir, en webpack.config.js

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

En el módulo js se puede leer como

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

Espero que esto ayude.



2

7
Nota: Si está utilizando la sintaxis ES6 (que ahora se recomienda) o componentes puros, los mixins no están disponibles. La recomendación es componer sus componentes. medium.com/@dan_abramov/…
Aren

1
esto parece una buena idea, ya que luego puede centralizar su lógica y luego pasar a Flux otros tipos de almacenamiento (por ejemplo, Localstorage o DB del lado del cliente)
dcsan

2
Esta respuesta debería haberse ampliado para incluir una muestra de código. Los enlaces pueden romperse.
vapcguy

0

Aquí hay un enfoque moderno que globalThisusamos para nuestra aplicación React Native .

globalThis ahora está incluido en ...


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 ( nuestro archivo de punto de entrada principal )

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

No sé qué están tratando de decir con estas cosas de "Reaccionar contexto"; me están hablando en griego, pero así es como lo hice:

Llevando valores entre funciones, en la misma página

En su constructor, vincule su setter:

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

Luego declara una función justo debajo de tu constructor:

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

Cuando quieras configurarlo, llama this.setSomeVariable("some value");

(Incluso podrías salirte con la tuya this.state.myProperty = "some value";)

Cuando quieras conseguirlo, llama var myProp = this.state.myProperty;

El uso alert(myProp);debería dartesome value .

Método de andamio adicional para transportar valores a través de páginas / componentes

Puede asignar un modelo a this(técnicamente this.stores), por lo que luego puede referenciarlo 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

Guarde esto en una carpeta llamada storescomo yourForm.jsx.

Entonces puedes hacer esto en otra página:

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

Si hubiera configurado this.state.someGlobalVariableotro componente usando una función como:

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

que enlaza en el constructor con:

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

el valor en propertyTextToAddse mostraría SomePageusando el código que se muestra arriba.


3
Perdón por ser nuevo aquí, pero acabo de aprender React y no estoy seguro de por qué esta respuesta recibe tantos
votos negativos

3
@someoneuseless ¡Exactamente! Y es por eso que me niego a borrarlo y hacer una reverencia a las masas. El hecho de que quieran usar "Contexto" (lo que sea) y estos otros objetos divertidos no significa que todos necesiten hacerlo. ¡Cinco altos!
vapcguy
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.