swe*_*let 3 immutable.js redux
在Redux中使用immutablejs时,我们将从combineReducers中获取一个常规的javascript对象,这意味着即使其中包含所有内容,它也不会是一个不可变的数据结构.这是不是意味着使用immutablejs将是徒劳的,因为无论如何都会在每个动作上创建一个全新的状态对象?
例:
const firstReducer = (state = Immutable.Map({greeting : 'Hey!'})) => {
return state
}
const secondReducer = (state = Immutable.Map({foo : 'bar'})) => {
return state
}
const rootReducer = combineReducers({
firstReducer, secondReducer
})
Run Code Online (Sandbox Code Playgroud)
将在每个动作上创建一个全新的状态对象
是,但combineReducers不会重新创建分配的状态切片.这有点类似于这样做:
const person = { name: 'Rob' };
const prevState = { person };
const nextState = { person };
Run Code Online (Sandbox Code Playgroud)
我创建了一个新的状态对象(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'
Run Code Online (Sandbox Code Playgroud)
回到Redux,一旦第一次调用所有reducers,他们就会初始化应用程序状态的切片,而你的应用程序的整个状态基本上等于这个:
{
firstReducer: Immutable.Map({greeting : 'Hey!'}),
secondReducer: Immutable.Map({foo : 'bar'}),
}
Run Code Online (Sandbox Code Playgroud)
请注意,这是一个普通对象.它具有保存Immutable对象的属性.
当一个动作被调度并通过每个reducer时,你得到它的方式,reducer只是再次返回现有的Immutable对象,它不会创建一个新的.然后将新状态设置为一个对象,该对象的属性firstReducer只是指向前一个状态所指向的同一个Immutable对象.
现在,如果我们不使用Immutable firstReducer:
const firstReducer = (state = {greeting : 'Hey!'}) => {
return state
}
Run Code Online (Sandbox Code Playgroud)
同样的想法,首次调用reducer时用作状态默认值的对象只是从前一个状态传递到下一个状态.内存中只有一个对象具有键greeting和值Hey!.有许多状态对象,但它们只有一个firstReducer指向同一对象的键.
这就是为什么我们需要确保我们不会意外地改变它,而是在我们改变它时更换它.你可以通过小心谨慎地完成这一点,但是使用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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
正确的方法是创建一个新的状态切片:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
Immutable给我们的另一个好处是,如果我们的reducer的状态切片碰巧还有很多其他数据greeting,那么Immutable可能会在引擎盖下进行一些优化,这样它就不必重新创建每一块数据.我们做的是更改单个值,但仍然同时确保不变性.这很有用,因为它可以帮助减少每次调度操作时放入内存的内容量.