Redux:Add/remove 来自嵌套 object/array,没有变异?

Redux: Add/remove from nested object/array, without mutating?

我认为 assign 应该创建一个新对象,这就是我在 reducer 中这样做的原因:

    case types.ADD_ATTRIBUTE:
      var newState = Object.assign({}, state)
      newState.attributes[action.industry].push(action.attribute)
      return Object.assign({}, state, newState);

    case types.REMOVE_ATTRIBUTE:
      var newState = Object.assign({}, state)
      var removeIndex = newState.attributes[action.industry].indexOf(action.attribute)
      newState.attributes[action.industry].splice(removeIndex, 1)
      return Object.assign({}, state, newState);

但是,当我这样做时,组件不会触发更新 (componentWillReceiveProps)。它确实收到了新的道具,但是 react-redux 内部 shouldComponentUpdate 没有检测到变化。

我做错了什么?

以下是处理 types.ADD_ATTRIBUTE 案例的方法:

Object.assign:

const newActionIndustry = state.attributes[action.industry].concat(action.attribute)

const newAttributes = Object.assign({}, state.attributes, {
  [action.industry]: newActionIndustry
})

const newState =  Object.assign({}, state, {
  attributes: newAttributes
})

使用此代码自行处理 types.REMOVE_ATTRIBUTE 案例。

如果您想重新渲染包含 attributes[action.industry] 的对象,您需要像处理状态一样重新创建此数组。

case types.ADD_ATTRIBUTE:
  return {
    ...state,
    attributes: {
      ...state.attributes,
      [action.industry]: [...state.attributes[action.industry], action.attribute]
    }
  }

case types.REMOVE_ATTRIBUTE:
  const removeIndex = newState.attributes[action.industry].indexOf(action.attribute)
  return {
    ...state,
    attributes: {
      ...state.attributes,
      [action.industry]: [
          ...state.attributes[action.industry].slice(0, removeIndex), 
          ...state.attributes[action.industry].slice(removeIndex + 1)
        ]
      }
   }

我最终决定这样做:(使用一些 ES6 魔法)

  case types.ADD_ATTRIBUTE:
      let newAttrState = state.attributes[action.industry].slice()
      newAttrState.push(action.attribute)
      return Object.assign({}, state, { attributes: { [action.industry]: newAttrState }} );

  case types.REMOVE_ATTRIBUTE:
      var newAttrState = state.attributes[action.userIndustry].slice()
      let removeIndex = newAttrState.indexOf(action.attribute)
      newAttrState.splice(removeIndex, 1)
      return Object.assign({}, state, { attributes: { [action.userIndustry]: newAttrState }} );

*更新:我现在意识到,正在覆盖整个 attributes 对象,只有一个动态键控数组,而我需要维持存储在该对象中的其他数组...

React-redux 的 shouldComponentUpdate() 对状态进行 浅层比较 以决定是否渲染。这种浅比较只检查对象的一层深度,这意味着如果你不改变状态本身的引用或它的任何一级属性,它不会触发组件的更新。

你的数组在 state.attributes[action.industry] 中嵌套得很深,你的动作不是修改状态或属性,所以 react-redux 不会更新你的组件。为了解决您的问题,您需要更改 attributes[action.industry],创建一个新数组(例如,使用 Array.concat() 而不是 Array.push() 或使用 attributes[action.industry] = [...attributes[action.industry], action.attribute ][= 中的扩展运算符17=]

或者,如果您使用的是有状态组件,您可以创建自己的 shouldComponentUpdate() 版本,考虑属性 属性 以决定是否呈现。