Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用不可变JS的Redux_Redux_Immutable.js - Fatal编程技术网

使用不可变JS的Redux

使用不可变JS的Redux,redux,immutable.js,Redux,Immutable.js,当将immutablejs与Redux一起使用时,我们将从CombineReducer获得一个常规javascript对象,这意味着即使其中的所有内容都是不可变的,它也不会是一个不可变的数据结构。这是否意味着使用immutablejs将是徒劳的,因为无论如何,每个操作都将创建一个全新的状态对象 例如: const firstReducer = (state = Immutable.Map({greeting : 'Hey!'})) => { return state } const

当将immutablejs与Redux一起使用时,我们将从CombineReducer获得一个常规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
})
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可能会在幕后进行一些优化,这样,如果我们只更改一个值,它就不必重新创建每一条数据,但同时仍然确保了不变性。这很有用,因为它可以帮助减少每次发送操作时内存中的内容量。

谢谢您的回答。我主要指的是内存使用和新对象的创建。罗布在回答中说得很清楚。啊,我明白了。常见问题解答还涉及此主题: