【问题标题】:How to declare a global variable in React?如何在 React 中声明一个全局变量?
【发布时间】:2015-12-18 08:57:23
【问题描述】:

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

请针对这些问题提出一个通用的解决方案,而不是 i18n 特定的解决方案。

【问题讨论】:

  • 您可以使用ReduxFlux 库来全局处理数据或状态。您可以轻松地将它传递给您的所有组件
  • 还有其他方法吗?我们在没有任何 React 框架的情况下启动了这个项目,因为它是 React 的早​​期版本。现在将每个组件连接到 Redux 商店需要付出巨大的努力。
  • react-global 这样的东西适合你吗?

标签: reactjs javascript-globalize


【解决方案1】:

超越反应

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

如果你想全局初始化一些东西但确保它只修改一次,你可以使用这个 singleton 方法,它最初具有可修改的属性,但是你可以在第一次使用后使用Object.freeze 来确保它的不可变在您的初始化场景中。

const myInitObject = {}
export default myInitObject

然后在你的 init 方法中引用它:

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

myInitObject 仍将是全局的,因为它可以在任何地方作为导入引用,但如果有人试图修改它,它将保持冻结并抛出。

使用单例的反应状态示例

https://codesandbox.io/s/adoring-architecture-ru3vt (参见 UserContext.tsx)

如果使用 react-create-app

(我实际上在寻找什么)在这种情况下,您还可以在引用环境变量时干净地初始化全局对象。

在项目的根目录下创建一个 .env 文件,其中包含前缀 REACT_APP_ 变量,效果非常好。您可以根据需要在 JS 和 JSX process.env.REACT_APP_SOME_VAR 中引用它,并且它在设计上是不可变的。

这避免了在 HTML 中设置 window.myVar = %REACT_APP_MY_VAR%

直接在 Facebook 上查看更多有用的详细信息:

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

【讨论】:

  • 老实说,这是一个很棒的提示,因为我使用的是服务器端渲染,所以我的身份验证令牌遇到了问题。我最终在第一次加载时从本地存储加载,然后将其存储到一个单独的配置文件中,我可以导入。很好的答案。
  • 这是迄今为止最好的答案!
  • 老兄,这让我大开眼界……谢谢你,从现在开始,我想我的 FE 开发者会好 20%:P
  • 哇!这是如此优雅的简单。谢谢你的分享,杰森!
  • 这真的很有帮助,谢谢分享。
【解决方案2】:

您为什么不尝试使用Context

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

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

正如在编写清晰的代码时最好避免使用全局变量一样,在大多数情况下您应该避免使用上下文。特别是,在使用它来“节省输入”并使用它而不是传递显式 props 之前,请三思。

【讨论】:

  • 关闭。但是 All 组件没有父子关系,并且 Context 在该树之外不起作用。我想要跨应用程序的 i18n。
  • @sapy 这就是为什么您应该使用 i18n 作为 redux 状态而不是上下文变量的原因,请在此处查看我的答案:stackoverflow.com/questions/33413880/…
  • 从我的角度来看,我建议使用 redux,特别是对于大型应用程序
  • 警告:这样的答案可能会触发 redux 专家。
【解决方案3】:

不推荐,但是....您可以使用应用程序类中的 componentWillMount 通过它添加全局变量...有点像这样:

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

仍然认为这是一个 hack……但它会完成你的工作

btw componentWillMount 在渲染之前执行一次,在这里查看更多: https://reactjs.org/docs/react-component.html#mounting-componentwillmount

【讨论】:

  • 这是针对某些用例的 hack。我正在将一个 React 应用程序集成到我公司的另一个非 React 应用程序的上下文中。这似乎是为消费应用程序公开公共方法的好方法。我错了吗?有没有更好的办法?
  • 还要注意 componentWillMount 已被弃用:reactjs.org/blog/2018/03/27/update-on-async-rendering.html
  • @mccambridge 我知道这已经晚了,但我会从非 React 应用程序向 React 发送一个函数,你会调用它来发送信息。顺便说一句,您可以使用 iframe 来做到这一点。
【解决方案4】:

在 ./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

【讨论】:

  • 是否可以在客户端更改此值?
  • @code-monkey 它在客户端
【解决方案5】:

这是一种现代方法,使用 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】:

    可以将全局变量保存在 webpack 中,即webpack.config.js

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

    在 js 模块中可以像这样读取

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

    希望这会有所帮助。

    【讨论】:

      【解决方案7】:

      到目前为止,我发现的最好方法是使用React Context,但将其隔离在high order provider component 中。

      【讨论】:

        【解决方案8】:

        【讨论】:

        【解决方案9】:

        GlobalThis 可能在某些浏览器中受支持。
        您可以参考以下链接
        https://webpack.js.org/plugins/provide-plugin/
        https://webpack.js.org/plugins/define-plugin/

        【讨论】:

          【解决方案10】:

          也许它正在使用大锤来破解坚果,但使用环境变量(使用 Dotenv https://www.npmjs.com/package/dotenv)您也可以在整个 React 应用程序中提供值。并且没有任何使用它们的开销代码。

          我来到这里是因为我发现在我的 env 文件中定义的一些变量在不同的 env 中都是静态的,所以我寻找一种方法将它们从 env 文件中移出。但老实说,我不喜欢我在这里找到的任何替代品。我不想在每次需要这些值时都设置和使用上下文。

          我在环境方面没有经验,所以如果这种方法有缺点,请告诉我。

          【讨论】:

            【解决方案11】:

            我不知道他们想用“React Context”的东西说什么——他们说的是希腊语,对我来说,但我是这样做的:

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

            在你的构造函数中,绑定你的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
            

            将其保存到名为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 中。

            【讨论】:

            • 很抱歉我是新手,但我刚学习 React,不知道为什么这个答案会受到如此多的反对
            • @someoneuseless 没错!这就是为什么我拒绝删除它并向群众磕头。仅仅因为他们想使用“上下文”(不管是什么)和这些其他有趣的对象并不意味着每个人都需要。高五!
            猜你喜欢
            • 2018-12-16
            • 1970-01-01
            • 2012-03-30
            • 2011-03-22
            • 2011-02-12
            • 2012-11-11
            • 2019-09-11
            • 1970-01-01
            • 2011-06-22
            相关资源
            最近更新 更多