在redux中,为什么我们必须将状态保持在reducers中不可变?

时间:2017-05-18 03:43:26

标签: reactjs redux frontend immutability

我想知道为什么我们应该让状态在减速器中保持不变。这是强制性的还是仅仅是推荐的方法? redux是否利用不变性来做一些优化?

经过一些实验,我发现redux确实利用了这种不变性的东西。一个证据就是当我们从reducer返回相同的状态引用时,即使状态中的数据发生了变化,UI也不会按原样进行更新。 如下例所示:



const reducer = (state = [], action) => {
	switch(action.type) {
		case 'BRING_UP_NEXT_IMAGE':
				state.push(state.shift());
				break;
		default: 
			return state;
	}
	return state;
};




用户界面没有更新,因为Redux检测到相同的状态引用(为了它的价值)。

这解释了如果我们想要更新UI,我们必须返回对状态的新引用。 但是为什么Redux要求内部状态结构也应该是不可变的呢?从我所看到的,UI是否仅仅更新取决于状态引用本身是否已更改。即使我改变内部结构,应用程序也能正常工作,如:



const reducer = (state = [], action) => {
	switch(action.type) {
		case 'BRING_UP_NEXT_IMAGE':
				state = state.concat(state.shift());
				break;
		default: 
			return state;
	}
	return state;
};




是的,我确实使用" state.shift()"来改变以前的状态,但由于state.concat返回对数组的新引用,因此状态本身是一个不同的引用,应用程序正常工作通常

简而言之,我想知道的是,状态是否应该严格保持不可变是必要的,以使Redux功能正确或推荐选项,以便应用程序可以通过在shouldComponentUpdate中进行浅层比较来实现更好的性能绕过对帐流程?

3 个答案:

答案 0 :(得分:2)

如果您认为" redux正常运行"当组件在他们订阅的商店更改时重新呈现时,如果您返回状态的新副本,它只能正常运行。

终极版' connect方法实现了一个默认的shouldComponentUpdate,它包含一个身份检查。

如果直接修改状态而不创建新标识,则不仅要修改新状态,还要修改旧状态,因为两者都指向商店中的相同引用。具有相同的引用将导致this.props.somePropFromStore === this.nextProps.somePropFromStore始终为true。除非您实现自定义行为,否则这将导致redux不再检测状态更改。

所以我会说它不仅仅是一个推荐的选项",因为如果你绕过redux的基本原则"永远不会改变数据"您可以使用保存所有信息的全局类存储变量替换redux存储引擎。

还原文档中还有一节解释它:http://redux.js.org/docs/faq/ReactRedux.html#why-isnt-my-component-re-rendering-or-my-mapstatetoprops-running

答案 1 :(得分:2)

我在博文Idiomatic Redux: The Tao of Redux, Part 1 - Implementation and Intent中深入讨论了这个问题。引用摘要部分:

  

核心Redux createStore函数本身对如何编写代码只有两个限制:操作必须是普通对象,并且它们必须包含已定义的type字段。它不关心不变性,可序列化或副作用,或type字段的实际价值。

     

那就是说,围绕该核心的常用部分,包括Redux DevTools,React-Redux,React和Reselect,依赖于不可变性的正确使用,可序列化的动作/状态和纯减速机功能。如果忽略这些期望,主应用程序逻辑可能正常工作,但是时间旅行调试和组件重新呈现很可能会中断。这些也会影响任何其他与持久性相关的用例。

     

同样重要的是要注意,Redux 不会以任何方式强制执行不变性,可序列化和纯函数。 reducer函数完全可以改变其状态或触发AJAX调用。应用程序的任何其他部分完全可以调用getState()并直接修改状态树的内容。将promises,函数,符号,类实例或其他非可序列化值放入操作或状态树中是完全可能的。你不是假设做任何这些事情,但它可能

Redux文档中Immutable Data FAQ section中讨论了Redux如何以及为何依赖不变性的详细信息。

答案 2 :(得分:0)

在反应生命周期方法componentWillReceivePropsshouldComponentUpdatecomponentWillUpdate中,如果你改变状态,nextProps和this.props将是相同的。它会产生难以调试的问题。