在React中使用不可变状态有什么缺点?

时间:2015-04-14 08:36:11

标签: javascript reactjs immutability immutable.js

我用“正常”方式构建了我的第一个具有有状态存储的React应用程序,现在我正在研究使用Este starterkit中使用的不可变全局状态。

  • 所有商店的状态保存在一个不可变的数据结构中
  • 组件没有状态,但基于商店getter函数在其render()中访问数据
  • 商店也是无状态的,但使用游标改变其域的全局应用程序状态。
  • 顶级应用程序组件侦听状态更改,并重新呈现整个组件树。
  • 组件被实现为“纯粹”意味着他们使用shouldComponentUpdate来有效地计算出它们在重新渲染中可以被跳过。

它以几种方式简化了应用程序结构:

  • 组件不会侦听商店,也不会将商店数据复制到本地状态。他们只是在每个渲染上抓住他们的商店状态。
  • 全局状态始终是整个应用程序的快照,使调试和添加撤消功能等功能变得更加容易。
  • 全局状态似乎简化了同构渲染。

我只读了关于在React中使用不可变数据的积极的事情,建议避免组件中的状态,所以我想知道是否有任何缺点。我认为必须有,否则我不明白为什么不推荐它作为构建React应用程序的 方式。

不变性对我来说是新的,如果我开始在复杂的真实应用程序中使用这种方法,我是否应该注意一些警告?

我能想到的唯一一件小事是在Este使用它时使用forceUpdate(),因为我读过它是一个同步函数。例如,Morearty似乎将更新推迟到下一个动画帧以便批量处理它们,但我认为这是一个实现细节/优化,而不是一些继承的不可变单态方法的缺点。

3 个答案:

答案 0 :(得分:13)

  1. 文档。 SO中一些投票最多的问题/咆哮是关于更新嵌套列表项的微不足道的事情,因为文档更倾向于熟悉函数式编程的观众,这使得其他人不太容易接受。
  2. 将模型层次结构知识与组件分开并非易事。我讨厌在组件中执行this.state.getIn("[parent, child, index]")因为它增加了模型更改破坏组件代码的可能性。这可以通过可扩展性(更多关于下面的内容)或通过帮助方法来预防,但是你肯定会失去普通JS成员的简单性。
  3. 我遇到的一个重大挑战是能够序列化和 反序列化状态。 fromJS方法支持自定义恢复 但它们是皮塔饼,需要仔细测试和维护。
  4. 记录类型被称为嵌套的弱化严重阻碍。这很令人遗憾,因为它允许更容易(相对而言)可扩展性,但仅鼓励单级层次结构。您无法轻松地从JSON创建嵌套记录。这使得很难将它们与常规的不可变fromJS用法混合,除非你使用上面提到的皮塔复兴。并且我提到了多么悲伤,因为Records将模型属性公开为第一类成员,确保模型完整性和默认值。
  5. 然后有可扩展性。尝试在不可变数据模型周围添加帮助程序以抽象组件中的模型层次结构依赖关系,并且您需要进行明显的跨栏竞赛。反序列化成为一场激烈的离婚之战。你需要乱搞复活,如果记录混合他们将会犯规,等等。更简单的可扩展性机制将大大有助于使我的组件代码更清晰。
  6. 没有记录最佳做法。尽管这与#1正确相关,但我仍然应该提到缺乏良好的文档会阻止人们选择最佳的做事方式。我不确定是否应该选择使用更新程序,或者使用forEach或setIn(等等)来更新不可变结构。这些方法不能相互交叉引用,以便让您知道有哪些替代方案。

答案 1 :(得分:6)

通过道具传递数据的一个优点是,您可以利用shouldComponentUpdate进行更高效的更新。如果您假设数据始终来自父级(例如通过道具),则可以有效地防止组件树的大部分必须重新渲染。不可变值使得这非常好,因为您可以在组件层次结构中相对较高的shouldComponentUpdate中引用相等性检查。

我在使用React使用不可变数据时发现的唯一另一个缺点是React开发人员工具不能很好地与它们一起工作(它们向您显示不可变值的底层数据结构而不是JS友好值)

答案 2 :(得分:3)

我知道答案已被接受,但我发现主要的缺点是你将非纯JavaScript对象传递给组件代码,这意味着你在从Immutable中读取值时不能使用常规JavaScript property accessors通过props传入的对象。相反,你必须use Immutable.js' read API。这是一个重要的权衡。你不能在商店里继续使用它所包含的Immutable.js;它现在已经在整个应用程序中泄漏了。当 Immutable.js被具有它自己的API或能够使用本机属性访问器的下一个buzzy Immutability库替换时,这可能是您感觉到的痛苦。此外,第三方代码几乎肯定会期望普通的旧JavaScript对象,因此在传递它们之前需要转换它们。如果您计划将Immutable.js引入现有应用程序,那么在组件代码中很快就会变得不清楚props是不可变的,哪些是JS对象,除非您非常自律并提出命名方案或在渲染链中传递对象时,您可以使用的其他一些方法。