在Redux中使用immutablejs时,我们将从combineReducers中获取一个常规的javascript对象,这意味着即使其中包含所有内容,它也不会是一个不可变的数据结构。这是不是意味着使用immutablejs将是徒劳的,因为无论如何都会在每个动作上创建一个全新的状态对象?
示例:
code
答案 0 :(得分:6)
将在每个动作上创建一个全新的状态对象
是,但不会重新创建由combineReducers
分配的状态切片。这有点类似于这样做:
const person = { name: 'Rob' };
const prevState = { person };
const nextState = { person };
我创建了一个新的状态对象(nextState
),但其person
键仍设置为与prevState
的{{1}}键完全相同的对象。内存中只有一个字符串person
的实例。
问题是当我改变'Rob'
对象时,我正在为多个状态改变它:
person
回到Redux,一旦第一次调用所有reducers,他们就会初始化应用程序状态的切片,而你的应用程序的整个状态基本上等于这个:
const person = { name: 'Rob' };
const prevState = { person };
person.name = 'Dan'; // mutation
const nextState = { person };
console.log(prevState.person.name); // 'Dan'
请注意,这是一个普通对象。它具有保存Immutable对象的属性。
当一个动作被调度并通过每个reducer时,你得到它的方式,reducer只是再次返回现有的Immutable对象,它不会创建一个新的。然后将新状态设置为具有属性{
firstReducer: Immutable.Map({greeting : 'Hey!'}),
secondReducer: Immutable.Map({foo : 'bar'}),
}
的对象,简单地指向前一个状态指向的同一个Immutable对象。
现在,如果我们没有对firstReducer
使用Immutable,那该怎么办?
firstReducer
同样的想法,当首次调用reducer时,用作状态默认值的对象只是从前一个状态传递到下一个状态。内存中只有一个对象具有键const firstReducer = (state = {greeting : 'Hey!'}) => {
return state
}
和值greeting
。有许多状态对象,但它们只有一个指向同一对象的键Hey!
。
这就是为什么我们需要确保我们不会意外地改变它,而是在我们改变它时更换它。你可以通过小心谨慎地完成这一点,但是使用Immutable使它更加万无一失。如果没有不可变,就可能搞砸了,并且这样做:
firstReducer
正确的方法是创建一个新的状态切片:
const firstReducer = (state = {greeting : 'Hey!'}, action) => {
switch (action.type) {
case 'CAPITALIZE_GREETING': {
const capitalized = state.greeting.toUpperCase();
state.greeting = capitalized; // BAD!!!
return state;
}
default: {
return state;
}
}
}
Immutable给我们的另一个好处是,如果我们的reducer的状态切片碰巧除了const firstReducer = (state = {greeting : 'Hey!'}, action) => {
switch (action.type) {
case 'CAPITALIZE_GREETING': {
const capitalized = state.greeting.toUpperCase();
const nextState = Object.assign({}, state, {
greeting: capitalized,
};
return nextState;
}
default: {
return state;
}
}
}
之外还有很多其他数据,那么Immutable可能会在引擎盖下进行一些优化,以便它没有如果我们所做的只是更改单个值,并且仍然同时确保不变性,则重新创建每个数据。这很有用,因为它可以帮助减少每次调度操作时放入内存的内容量。
答案 1 :(得分:2)
combineReducers()
确实为您提供了一个普通的根对象。
这本身不是问题 - 只要不改变它们就可以将普通对象与Immutable对象混合。所以你可以忍受这个就好了。
您也可以使用返回不可变地图的alternative combineReducers()
。这完全取决于你,并没有任何重大区别,只是它允许你在任何地方使用Immutable。
不要忘记combineReducers()
实际上是easy to implement on your own。
这是不是意味着使用immutablejs是徒劳的,因为无论如何都会在每个动作上创建一个全新的状态对象?
我不确定你的意思是“徒劳”。 Immutable不会神奇地阻止创建对象。当您在不可变set()
中Map
时,您仍然会创建一个新对象,只是(在某些情况下)更有效。无论如何,当你有两把钥匙时,这并没有什么不同。
所以不在这里使用Immutable并没有任何缺点,除了你的应用程序在选择数据结构时稍微不那么一致。