redux的reducer为什么要设计成不能直接修改原状态,而返回修新状态对象

网上的文章一般从两个角度回答这个问题:
第一,从源码角度,因为redux会对reducer返回的状态进行引用地址的比较,不同才更新,所以直接修改旧状态不会更新。
第二,从设计角度,如果要知道reducer返回的状态是否有变化,必须进行状态对象的深度比较,这样比较消耗性能,所以仅进行状态对象引用地址的比较,由开发者来决定是否更新,返回新状态才更新。

感觉网上的文章还是没有解释清楚redux为什么这么设计。如果reducer设计成可直接修改原状态的函数,那么也就没有必要进行新旧状态对象的比较了,因此根本不存在深度比较的问题。为什么redux不这么设计呢?

阅读 6.7k
3 个回答

因为reducer秉持的理念是纯函数吧,固定的输入会有固定的输出。如果直接修改原状态,那么就不会有输出了,违背了纯函数的原则。

另外,原对象作为reducer的入参,修改原对象就相当于修改了参数,这是一种副作用,同样违背了纯函数的原则。

至于为什么设计成纯函数,目的就是不改变原有状态,最终的目标是实现redux时间旅行的特性,让action变得可追踪。正如chrome插件redux-dev-tools中的交互,可以点击任意时刻的action看到那时的state是什么样的。
image.png

一个action对应一个新的状态,可以方便地将action和state对应起来。假设直接改变原有状态,将使状态变得难以追踪。

如果reducer设计成可直接修改原状态的函数,那么也就没有必要进行新旧状态对象的比较了,因此根本不存在深度比较的问题

为什么会有这样的理解呢
比较还是要比较的,即使是vue这种明确知道那个对象改变了,最终还是要比较两棵树的

首先你自己说的两点就是redux如此设计的原因

再解答这个问题

如果reducer设计成可直接修改原状态的函数,那么也就没有必要进行新旧状态对象的比较了,因此根本不存在深度比较的问题。为什么redux不这么设计呢?

按照如上思路的话,就相当于是redux提供了一个类似React的forceUpdate的方法,只要调用了这个方法,视图就会重新渲染,不需要做判断比较什么的,就如是你说的

没有必要进行新旧状态对象的比较了,因此根本不存在深度比较的问题

那么此时就存在一个权衡利弊,到底是视图直接渲染的消耗大,还是做对比的消耗大。
redux选择了一个折中的方案,会根据新旧属性做对比,但是仅仅比较的是引用地址是否相同,这样既减少了视图直接渲染的消耗,也减少了数据对比的消耗

其实我们也可以从forceUpdate这个api不推荐使用的原因得到类似的道理

https://zh-hans.reactjs.org/docs/react-component.html#forceupdate

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题