如何在React应用程序中避免全局状态?

时间:2015-11-16 12:29:37

标签: javascript dependency-injection reactjs global-variables global-state

在我的React应用程序中,我需要存储一些需要几乎无处可访问的数据,但不希望将其保存在全局(即静态)数据结构中,以便可以轻松模拟我的单元测试和风格指南。

我的意思是数据:

  • 常量IN_BROWSER,在浏览器版本中为true,在节点中为false
  • 在浏览器启动时初始化的常量IS_MOBILE
  • 当前登录用户的数据
  • 我连接到的API的url(这是localhost,登台服务器或生产,具体取决于配置)

现在我有一个名为sessionData.js的文件来存储这些数据,每当我需要时,我会在代码中require('./sessionData')使用它。我可以使用rewire为我的单元测试模拟它,并且,因为它们顺序运行,它现在可以正常工作。风格指南存在问题,因为每个示例都可以从不同用户的角度显示视图(理想情况下,每个示例都有自己的sessionData)。

IN_BROWSER目前是global,这也是一个坏主意,因为它会对每个模块的初始化代码产生隐式依赖。

我看到我可以通过道具将我的sessionData和其他内容传递给层次结构中的每个组件,但这似乎有很多冗余。

是否有任何设计模式可以更好地解决它?

4 个答案:

答案 0 :(得分:1)

我使用Webpack,有一个名为DefinePlugin的插件可以处理这个问题。 我想这是一个很好的做法,因为它是我放置大部分应用配置细节的地方。

例如,我的webpack配置包含:

new webpack.DefinePlugin({
  'process.env': {'NODE_ENV': JSON.stringify(options.env)}
}),

所以我可以像前端一样在前端使用process.env.NODE_ENV

我在这里打开了我的webpack配置:https://github.com/agendor/react-webpack-sample/blob/master/webpack.config.js

这是一个link for the plugin documentation

对于单元测试,我使用一个test-helper.js类定义一些全局变量,我在每次测试开始时都需要它。我不确定这是不是一个好的做法,但它对我们的项目工作正常。我们在没有webpack的情况下运行测试。也许更好的做法是为处理其中一些全局变量的测试提供特定的webpack配置。

答案 1 :(得分:1)

如果我正确理解你,为什么不通过道具将数据结构传递给可能需要它的所有组件?显然你不能通过道具来修改它,但在这个数据结构中你总是可以包含一个回调函数来更新它,具有如下结构的东西:

structure = {
  dataItem1: stuff,
  dataItem2: stuff2,
  dataItemCallback: { var foo = stuff here; }
}

然后你可以这样称呼:

this.props.structure.dataItem1;
this.props.structure.dataItem2;

要更新您可以随时致电的内容:

this.props.structure.dataItemCallback(newData);

此外,如果您通过道具传递它,现在所有组件都可以重新渲染,如果结构中的任何内容发生变化。

答案 2 :(得分:0)

看起来react context是可行的方法。

不幸的是,API目前不稳定,例如React.withContext在0.13-alpha中被弃用,文档说API将来会发生变化,但似乎是这样的上下文isn't going to be deprecated

答案 3 :(得分:0)

在某些情况下,可以重构组件以直接传递所需的数据,而不是将其置于全局状态。这不能解决问题,但可以大大减少它。这是一个nice explanation from Dan Abramov

enter image description here