为什么 Redux 中的对象应该是不可变的?我知道某些框架(例如 Angular2)将使用 onPush 并且可以利用不变性来比较视图状态以加快渲染速度,但我想知道是否还有其他原因,因为 Redux 与框架无关,但它在自己的文档中提到要使用不变性(与框架无关)。
感谢任何反馈。
为什么 Redux 中的对象应该是不可变的?我知道某些框架(例如 Angular2)将使用 onPush 并且可以利用不变性来比较视图状态以加快渲染速度,但我想知道是否还有其他原因,因为 Redux 与框架无关,但它在自己的文档中提到要使用不变性(与框架无关)。
感谢任何反馈。
Redux 是一个将状态表示为(不可变)对象的小型库。和新的状态通过使当前状态通过纯函数来创建一个全新的对象/应用程序状态。
如果你的眼睛盯着那边,别担心。总而言之,Redux 不会通过修改对象来表示应用程序状态的变化(就像使用面向对象的范例一样)。而是将状态更改表示为输入对象和输出对象 ( )之间的差异var output = reducer(input)
。如果你改变了input
或者output
你使状态无效。
换句话说,不变性是 Redux 的要求,因为 Redux 将您的应用程序状态表示为“冻结对象快照”。使用这些离散快照,您可以保存您的状态或反转状态,并且通常对所有状态更改都有更多的“说明”。
您的应用程序的状态仅由一类称为 reducer 的纯函数更改。Reducers 有两个重要的属性:
function name(state, action) {}
,所以很容易组合它们:假设状态如下所示:
var theState = {
_2ndLevel: {
count: 0
}
}
我们想增加计数,所以我们制作了这些减速器
const INCR_2ND_LEVEL_COUNT = 'incr2NdLevelCount';
function _2ndlevel (state, action) {
switch (action.type) {
case INCR_2ND_LEVEL_COUNT:
var newState = Objectd.assign({}, state);
newState.count++
return newState;
}
}
function topLevel (state, action) {
switch (action.type) {
case INCR_2ND_LEVEL_COUNT:
return Object.assign(
{},
{_2ndLevel: _2ndlevel(state._2ndlevel, action)}
);
}
}
注意Object.assign({}, ...)
在每个reducer 中创建一个全新的对象的用法:
假设我们已经将 Redux 连接到这些 reducer,那么如果我们使用 Redux 的事件系统来触发状态更改......
dispatch({type: INCR_2ND_LEVEL_COUNT})
...Redux 将调用:
theNewState = topLevel(theState, action);
注意:action
来自dispatch()
现在theNewState
是一个全新的对象。
注意:您可以使用库(或新语言功能)来强制执行不变性,或者小心不要改变任何东西:D
为了更深入地了解,我强烈建议您查看Dan Abramov(创作者)的这段视频。它应该回答您的任何挥之不去的问题。
Redux 文档中提到了以下不变性的好处:
- Redux 和 React-Redux 都使用浅层相等性检查。特别是:
- Redux 的 combineReducers 实用程序会浅层检查由它调用的 reducer 引起的引用更改。
- React-Redux 的 connect 方法生成组件,这些组件会浅层检查对根状态的引用更改,以及 mapStateToProps 函数的返回值,以查看包装的组件是否确实需要重新渲染。这种浅层检查需要不变性才能正常运行。
- 不可变数据管理最终使数据处理更安全。
- 时间旅行调试要求reducer是没有副作用的纯函数,这样你才能正确地在不同状态之间跳转。
Redux 使用不变性的主要原因是它不必遍历对象树来检查每个键值的变化。相反,它只会检查对象的引用是否更改,以便在状态更改时更新 DOM。
伟大的文章https://medium.cobeisfresh.com/how-redux-can-make-you-a-better-developer-30a094d5e3ec
与不可变数据一样,纯函数是函数式编程的核心概念之一