如何在React中声明全局变量?


106

i18n在一个组件(在应用程序中加载的第一个组件)中初始化了翻译对象。所有其他组件都需要相同的对象。我不想在每个组件中重新初始化它。怎么回事?使它可用于窗口范围并没有帮助,因为我需要在render()方法中使用它。

请提出针对这些问题的通用解决方案,而不是针对国际化的解决方案。


1
您可以使用ReduxFlux可以全局处理数据或状态的库。您可以轻松地将其传递给所有组件
vistajess 2015年

还有其他方法吗?我们开始这个项目时没有任何React Framework,因为那是React的早期。现在,将每个组件连接到Redux商店将需要付出巨大的努力。
2015年

3
react-global这样的东西对您有用吗?
TwoStraws 2015年

Answers:


50

为什么不尝试使用Context

您可以在任何父组件中声明一个全局上下文变量,并且可以通过整个组件树访问此变量this.context.varname。您只需要在父组件中指定childContextTypesgetChildContext然后就可以通过contextTypes在子组件中进行指定而在任何组件中使用/修改它。

但是,请注意文档中提到的这一点:

正如在编写清晰的代码时最好避免使用全局变量一样,在大多数情况下也应避免使用上下文。特别是,在使用它“保存类型”并使用它而不是传递显式道具之前,请三思。


30
关 。但是所有组件都没有父子关系,上下文在那棵树之外也无法工作。我想要整个应用程序中的i18n。
2015年

@sapy这就是为什么你应该使用国际化的终极版状态不是作为一个上下文变量看我的答案在这里:stackoverflow.com/questions/33413880/...
法里德Alnamrouti

9
可怕的答案。
r3wt

从我的身边,我会建议使用终极版,而是和专为大型应用
胡斯尼奔

37

超越React

您可能不知道导入已经是全局的。如果导出对象(单个),则可以将其作为导入语句全局访问,也可以全局修改

如果要全局初始化某件事,但确保仅对其进行一次修改,则可以使用这种最初具有可修改属性的单例方法,但是Object.freeze在首次使用后可以使用它来确保其在初始化方案中不可变

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_很好。您可以process.env.REACT_APP_SOME_VAR根据需要在JS和JSX中进行引用,并且它在设计上是不可变的。

这样避免了必须window.myVar = %REACT_APP_MY_VAR%在HTML 中进行设置。

直接从Facebook查看有关此内容的更多有用信息:

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


6
老实说,这是一个很好的提示,因为使用服务器端渲染,所以我的身份验证令牌遇到了麻烦。我最终在第一次加载时从localstorage加载,然后将其存储到我可以导入的单独的Config文件中。好答案。

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
对于某些用例来说,这是一个hack。我正在将React应用程序集成到我公司的另一个非React应用程序的上下文中。这似乎是公开使用应用程序的公共方法的好方法。我错了吗?有没有更好的办法?
mccambridge

2
另请注意,它componentWillMount已被弃用:reactjs.org/blog/2018/03/27/update-on-async-rendering.html
RyanNerd

@mccambridge我知道这已经晚了,但是我会将非反应应用程序中的函数发送到React中,您将调用该函数来发送信息。顺便说一句,您可以使用iframe进行此操作。
Nic Szerman '18

6

使用以下内容在./src文件夹中创建一个名为“ config.js”的文件:

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

7
注意:如果您使用的是ES6语法(现已推荐)或纯组件,则不能使用mixins。建议是组成您的组件。medium.com/@dan_abramov / ...
Aren

1
这似乎是一个好主意,因为您可以集中化逻辑,然后再转移到Flux其他类型的存储(例如Localstorage或客户端DB)
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

我不知道他们想用这种“反应上下文”的东西说什么-他们在跟希腊人说话,但是这是我的做法:

在同一页上的函数之间携带值

在构造函数中,绑定您的setter:

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

将此保存到名为的文件夹storesyourForm.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);

输入的值propertyTextToAddSomePage使用上面显示的代码显示。


3
抱歉,在这里是新手,但我只是学习React,不知道为什么这个答案会被
否决

3
@someoneuseless就是这样!这就是为什么我拒绝删除它并向大众to头。仅仅因为他们想要使用“上下文”(无论是什么)以及这些其他有趣的对象,并不意味着每个人都需要。举手击掌!
vapcguy
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.