当在 Redux 中使用 immutablejs 时,我们将从 combineReducers 返回一个常规的 javascript 对象,这意味着它不会是一个不可变的数据结构,即使其中的所有内容都是。这是否意味着使用 immutablejs 将是徒劳的,因为无论如何都会在每个 Action 上创建一个全新的状态对象?
例子:
const firstReducer = (state = Immutable.Map({greeting : 'Hey!'})) => {
return state
}
const secondReducer = (state = Immutable.Map({foo : 'bar'})) => {
return state
}
const rootReducer = combineReducers({
firstReducer, secondReducer
})
最佳答案
是的,但不会重新创建由 combineReducers
分配的该状态的切片。这有点类似于这样做:
const person = { name: 'Rob' };
const prevState = { person };
const nextState = { person };
我创建了一个新的状态对象 (
nextState
),但它的 person
键仍然设置为与 prevState
的 person
键相同的对象。内存中只有一个字符串 'Rob'
的实例。问题是当我改变
person
对象时,我正在为多个状态更改它:const person = { name: 'Rob' };
const prevState = { person };
person.name = 'Dan'; // mutation
const nextState = { person };
console.log(prevState.person.name); // 'Dan'
回到 Redux,一旦所有的 reducer 都被第一次调用,它们就会初始化它们的应用程序状态的切片,你的应用程序的整个状态基本上等于这个:
{
firstReducer: Immutable.Map({greeting : 'Hey!'}),
secondReducer: Immutable.Map({foo : 'bar'}),
}
请注意,这是一个普通对象。它具有保存不可变对象(immutable对象)的属性。
当一个 Action 被分派(dispatch)并通过每个 reducer 时,你得到它的方式, reducer 只是再次返回现有的不可变对象(immutable对象),它不会创建一个新的对象。然后将新状态设置为具有属性
firstReducer
的对象,该对象简单地指向前一个状态所指向的同一个不可变对象(immutable对象)。现在,如果我们不为
firstReducer
使用 Immutable 会怎样:const firstReducer = (state = {greeting : 'Hey!'}) => {
return state
}
同样的想法,当第一次调用 reducer 时用作状态默认值的对象只是从前一个状态传递到下一个状态。内存中只有一个对象具有键
greeting
和值 Hey!
。有许多状态对象,但它们只有一个指向同一个对象的键 firstReducer
。这就是为什么我们需要确保我们不会意外地改变它,而是在我们改变它时替换它。当然,只要小心一点,您可以在没有 Immutable 的情况下完成此操作,但使用 Immutable 使其更加万无一失。如果没有 Immutable,就有可能搞砸并执行以下操作:
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;
}
}
}
正确的方法是创建一个新的状态切片:
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 给我们的另一个好处是,如果我们的 reducer 的状态切片碰巧除了
greeting
之外还有很多其他数据,Immutable 可能会在幕后做一些优化,这样它就不必重新创建每条数据,如果我们所做的只是改变一个值,同时仍然确保不变性。这很有用,因为它可以帮助减少每次分派(dispatch)操作时放入内存的内容量。关于带有不可变 JS 的 Redux,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36571348/