3

I thought assign was supposed to make a new object, that's why I did this in my 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);

However, when I do this, the component will not trigger an update (componentWillReceiveProps). It does receive the new props, but the react-redux internal shouldComponentUpdate does not detect changes.

What am I doing wrong here?

0

4 Answers 4

4

In case if you want to re-render object containing attributes[action.industry], you need to recreate this array same as you do with 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)
        ]
      }
   }
Sign up to request clarification or add additional context in comments.

Comments

0

I eventually settled on this: (with some ES6 magic)

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

*Update: Which I now realize, is overriding the whole attributes object, with only one dynamically keyed array, while I need to sustain the other arrays stored in that object...

Comments

0

React-redux's shouldComponentUpdate() does a shallow comparison of the state in order to decide to render or not. This shallow comparison checks only one level depth of the object, it means that if you don't change the reference of the state itself or any of its first-level properties, it won't trigger an update of the component.

Your array is deeply nested in state.attributes[action.industry], and your action is not modifying state nor attributes, so react-redux won't update your component. In order to solve your problem, you need to change attributes[action.industry], creating a new array (e.g. using Array.concat() instead of Array.push() or using the spread operator like in attributes[action.industry] = [...attributes[action.industry], action.attribute ]

Alternatively, if you are using a stateful component you can create your own version of shouldComponentUpdate() that takes into account the attributes property in order to decide to render or not.

Comments

0

Here's how you could handle the types.ADD_ATTRIBUTE case:

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

Handle the types.REMOVE_ATTRIBUTE case by yourself using this code.

2 Comments

This works, I however fail to see the difference between the two examples? (both use ES6?)
I still don't see any spread operators, or any difference in the 2 codes...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.