使用不可变JS的Redux
当将immutablejs与Redux一起使用时,我们将从CombineReducer获得一个常规javascript对象,这意味着即使其中的所有内容都是不可变的,它也不会是一个不可变的数据结构。这是否意味着使用immutablejs将是徒劳的,因为无论如何,每个操作都将创建一个全新的状态对象 例如:使用不可变JS的Redux,redux,immutable.js,Redux,Immutable.js,当将immutablejs与Redux一起使用时,我们将从CombineReducer获得一个常规javascript对象,这意味着即使其中的所有内容都是不可变的,它也不会是一个不可变的数据结构。这是否意味着使用immutablejs将是徒劳的,因为无论如何,每个操作都将创建一个全新的状态对象 例如: const firstReducer = (state = Immutable.Map({greeting : 'Hey!'})) => { return state } const
const firstReducer = (state = Immutable.Map({greeting : 'Hey!'})) => {
return state
}
const secondReducer = (state = Immutable.Map({foo : 'bar'})) => {
return state
}
const rootReducer = combineReducers({
firstReducer, secondReducer
})
Redux附带的combineReducers()
确实为您提供了一个普通的根对象
这本身并不是一个问题,你可以把普通对象和不可变对象混合在一起,只要你不改变它们。所以你可以很好地接受这个
您也可以使用返回不可变映射的。这完全取决于您,除了它允许您在任何地方都使用Immutable之外,没有什么大的区别
不要忘记,combineReducers()
实际上是
这是否意味着使用immutablejs将是徒劳的,因为无论如何,每个操作都将创建一个全新的状态对象
我不知道你说的“白费力气”是什么意思。Immutable不会神奇地阻止创建对象。当您在不可变的映射中set()
时,仍然可以创建一个新对象,只是(在某些情况下)效率更高。当你有两个钥匙在里面的时候,这并没有什么区别
因此,在这里不使用Immutable并没有任何负面影响,除了您的应用程序在数据结构选择上的一致性稍差之外
每个动作都将创建一个全新的状态对象
是,但不会重新创建由组合传感器分配的该状态的片。这有点类似于这样做:
const person = { name: 'Rob' };
const prevState = { person };
const nextState = { person };
我创建了一个新的state对象(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,一旦第一次调用了所有还原程序,它们将初始化应用程序状态的切片,并且应用程序的整个整体状态基本上等于:
{
firstReducer: Immutable.Map({greeting : 'Hey!'}),
secondReducer: Immutable.Map({foo : 'bar'}),
}
请注意,这是一个普通对象。它具有保存不可变对象的属性
当一个动作被调度并通过每个reducer时,reducer只会返回现有的不可变对象,而不会创建一个新的对象。然后将新状态设置为一个对象,该对象的属性firstReducer
仅指向前一状态指向的同一个不可变对象
现在,如果我们没有为firstReducer
使用Immutable会怎么样:
const firstReducer = (state = {greeting : 'Hey!'}) => {
return state
}
同样,当第一次调用reducer时用作默认状态的对象只是从上一个状态传递到下一个状态。内存中只有一个对象具有键问候语和值嘿代码>。有许多状态对象,但它们只是有一个指向同一对象的键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;
}
}
}
正确的方法是创建一个新的状态片:
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的状态片碰巧有很多其他数据,而不仅仅是问候语
,Immutable可能会在幕后进行一些优化,这样,如果我们只更改一个值,它就不必重新创建每一条数据,但同时仍然确保了不变性。这很有用,因为它可以帮助减少每次发送操作时内存中的内容量。谢谢您的回答。我主要指的是内存使用和新对象的创建。罗布在回答中说得很清楚。啊,我明白了。常见问题解答还涉及此主题: