我是Redux的新手 - 而且我真的想要全面了解使用函数式编程来使单向数据更加优雅。
我看到它的方式 - 每个reducer都采用旧状态,创建一个新状态而不改变旧状态,然后将新状态传递给下一个reducer以执行相同操作。
我认为不会造成副作用有助于我们获得单向数据流的好处。
我真的不知道不改变旧状态的重要性。
我唯一能想到的可能是我读过的“时间旅行”,因为如果你坚持每个州,你就可以表演并“撤消”。
问题:
还有其他原因导致我们不想在每一步都改变旧状态吗?
答案 0 :(得分:30)
如果做得好,使用不可变数据结构会对性能产生积极影响。在React的情况下,如果数据没有改变,性能通常是避免不必要的重新呈现应用程序。
要实现这一点,您需要将应用的下一个状态与当前状态进行比较。如果状态不同:重新渲染。否则不要。
要比较状态,您需要比较状态中的对象是否相等。在普通的旧JavaScript对象中,您需要进行深度比较,以查看对象中的任何属性是否发生了变化。
使用不可变对象,您不需要它。
immutableObject1 === immutableObject2
基本上就是诀窍。或者,如果您使用的是像Immutable.js Immutable.is(obj1, obj2)
这样的库。
就反应而言,您可以将其用于shouldComponentUpdate
方法,就像流行的PureRenderMixin
一样。
shouldComponentUpdate(nextProps, nextState) {
return nextState !== this.state;
}
当状态没有改变时,此功能可防止重新渲染。
我希望,这有助于推断不可变对象背后的推理。
答案 1 :(得分:6)
“无突变”口头禅的关键是如果你不能改变对象,你就不得不创建一个新的(具有原始对象的属性加上新对象的属性) )。
要在调度操作时更新组件, Redux会检查对象是否不同,而不是属性是否已更改(这要快得多),所以:
答案 2 :(得分:4)
我对Redux(和React.js)也很陌生,但这是我从学习这些东西中理解的。
为什么选择不可变状态而不是可变状态有几个原因。
首先,突变跟踪非常困难。例如,当您在多个代码段中使用变量并且可以在每个位置修改变量时,您需要处理每个更改并同步变异结果。
在许多情况下,这种方法会导致双向数据流。数据片段在函数,变量等中上下流动。代码开始受到if-else
构造的污染,这些构造负责处理状态变化。
当您添加一些异步调用时,您的状态更改可能更难以跟踪。
当然,我们可以订阅数据事件(例如Object.observe
),但这可能会导致错过更改的某些应用程序部分与程序的其他部分不同步。
不可变状态可帮助您实现单向数据流,帮助您处理所有更改。首先,数据从上到下流动。这意味着应用于主模型的所有更改都将推送到较低的组件。您始终可以确保应用程序的所有位置的状态都相同,因为它只能从代码中的一个位置更改 - reducers。 还有一件事值得一提 - 您可以在多个组件中重用数据。状态无法更改(可以创建新的状态),因此在几个地方使用相同的数据非常安全。
您可以在此处找到有关可变性的优缺点的更多信息(以及选择它作为Redux主要方法的原因):
答案 3 :(得分:4)
Redux通过比较两个对象的内存位置来检查旧对象是否与新对象相同。如果你在reducer中改变了旧对象的属性,那么“new state”和“old state”都将指向同一个对象,Redux将推断没有任何改变。
答案 4 :(得分:0)
没有理由。没有任何根本原因,shouldComponentUpdate“纯渲染”优化不能与可变状态容器一起使用。例如,这个库就是这样做的。
https://github.com/Volicon/NestedReact
对于不可变数据,对数据结构本身的引用可以用作版本标记。因此,比较您正在比较版本的参考文献。
对于可变数据,您需要引入(和比较)单独的版本令牌,这很难手动完成,但可以使用智能“可观察”对象轻松实现。