Redux:在嵌套对象/数组中添加/删除,而不进行变异?

时间:2016-08-26 08:34:22

标签: reactjs redux react-redux

我认为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未检测到更改。

我在这里做错了什么?

4 个答案:

答案 0 :(得分:4)

如果你想重新渲染包含attributes[action.industry]的对象,你需要像使用state一样重新创建这个数组。

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)
        ]
      }
   }

答案 1 :(得分:0)

以下是处理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个案。

答案 2 :(得分:0)

我最终确定了这一点:(有一些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对象,只有一个动态键控数组,而我需要维持存储在该对象中的其他数组......

答案 3 :(得分:0)

React-redux' s shouldComponentUpdate()执行州的浅层比较以决定是否渲染。这种浅层比较仅检查对象的一个​​级别深度,这意味着如果您不更改状态本身或其任何第一级属性的引用,它将不会触发组件的更新

您的数组已深深嵌套在state.attributes[action.industry]中,您的操作不会修改状态或属性,因此react-redux不会更新您的组件。为了解决您的问题,您需要更改attributes[action.industry],创建新数组(例如使用Array.concat()代替Array.push()或使用attributes[action.industry] = [...attributes[action.industry], action.attribute ]中的扩展运算符

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