在react redux reducer中替换new state而不创建副本



如果我已经完全替换了状态片的全部,我还需要使用Object吗?分配或扩展操作符来复制原始状态并将其替换为新状态,或者我可以在我的减速器中返回新状态?

const fetching = (state = { isFetching: false }, action) => {
  switch (action.type) {
    case 'REQUESTING':
      return Object.assign({}, state, { isFetching: true } )
    case 'RECEIVE_POKEMON_TYPE_INFO':
      return Object.assign({}, state, { isFetching: false } )
    default:
      return state
  }
}

const fetching = (state = { isFetching: false }, action) => {
  switch (action.type) {
    case 'REQUESTING':
      return { isFetching: true }
    case 'RECEIVE_POKEMON_TYPE_INFO':
      return { isFetching: false }
    default:
      return state
  }
}

这里发生了几件事。基本上,如果您的状态只有由布尔变量组成,那么通过枚举创建新对象是可以的。然而,如果你的状态由其他东西组成,那么做一个对象。分配应该工作。

然而(并不是总是有一个'然而'),如果你的状态是复杂的-那就是它由其他对象组成,然后做对象。Assign不会正确地复制字段——它复制的是引用而不是值。例如,如果你的状态包含一个"currentlySelectedPokemon"字段,那么值就是一个Pokemon对象,然后是object。Assign将复制一个对pokemon对象的引用。它不会复制对象本身。为了更容易地显示这一点,请看下面的代码——它为obj2打印"value2"。

var obj1 = {
  field: {
    subfield: "value"
  }
};
var obj2 = Object.assign({}, obj1);
obj1.field.subfield = "value2";
console.log(JSON.stringify(obj2, null, 2));

有两种方法可以解决这个问题。第一种方法是对所有状态使用不可变库。然而,我发现将复杂对象转换为不可变对象并将其转换为不可变对象的开销提供了足够的复杂性,从而引入了不必要的bug。所以现在我这样做:

const fetching = (state = { isFetching: false }, action) => {
  switch (action.type) {
    case 'REQUESTING':
      const newState = JSON.parse(JSON.stringify(state));
      newState.isFetching = true;
      return newState;
    case 'RECEIVE_POKEMON_TYPE_INFO':
      const newState = JSON.parse(JSON.stringify(state));
      newState.isFetching = false;
      return newState;
    default:
      return state
  }
}

事实证明JSON.parse(JSON.stringify(object))是一种快速可靠的方式来复制一个普通java对象。它剥离了所有的功能(这是我通常想要的)。而且速度很快,因为浏览器通常用本地代码实现这些功能。

您可以使用Object.assignspread operator,如下图

using Object.assign:

const fetching = (state = { isFetching: false }, action) => {
  switch (action.type) {
    case 'REQUESTING':
      return Object.assign({}, state, { isFetching: true } )
    case 'RECEIVE_POKEMON_TYPE_INFO':
      return Object.assign({}, state, { isFetching: false } )
    default:
      return state
  }
} 

使用扩展操作符:

const fetching = (state = { isFetching: false }, action) => {
  switch (action.type) {
    case 'REQUESTING':
      return { ...state, isFetching: true }
    case 'RECEIVE_POKEMON_TYPE_INFO':
      return { ...state, isFetching: false }
    default:
      return state
  }
} 

使用Object.assign()可以快速使简单的reducer难以读取,因为verbose syntax . spread (...)运算符以更简洁的方式将可枚举属性从一个对象复制到另一个对象。

相关内容

最新更新