7

I'm working with Redux and recently ran into a problem where I was adding messages to an array and the Redux state was not issueing a re-render on React. I'm using the react-redux library for this. Here's an example of the problem I was having:

// State structure
structure: { messages: {}, groups: {} }

// ---
newState = { ...prevState };
newState.messages[action.message.group] = action.message;
return newState; 

This was updating the state however it wasn't triggering an update to the react component, however replacing newState = { ...prevState } with newState = JSON.parse(JSON.stringify(prevState)) resolved the issue.

Could anyone explain why this is happening in detail? I was under the impression that the spread operator created a clone of the object and I've never had any problems with it until now.

2
  • I think you should use this "Object.assign". without directly replace origin value, because we don't mutate the state in generally. (redux.js.org/docs/basics/Reducers.html) Commented Apr 20, 2017 at 2:30
  • The spread operator is only a shallow copy, not a deep copy like your serialize/deserialize approach. That could affect things. Commented Apr 20, 2017 at 2:45

2 Answers 2

9

react-redux connected components do a shallow strict equality check to decide if they want to update. see http://redux.js.org/docs/faq/ImmutableData.html

The spread operator is like Object.assign and does not deeply clone an object. The reason the JSON thing worked is because you created a whole new object which would pass the strict equality check, however all your components would update needlessly because nothing will pass a strict equality check now.

Object.assign({}, ...prevState, ...newState) would create a new top-level object, but it would not create a new object for any objects nested in prevState or newState. However, you would have to carefully update nested objects so as to avoid needless re-renders. This can get tricky for deeply nested objects and arrays.

I'd recommend checking out the seamless-immutable or immutable packages for managing state. Also, the reselect library can help you extract memoized objects specific to your component's needs.


UPDATE 08/16/2020

the immer library is one of the best state management libraries as of today

Sign up to request clarification or add additional context in comments.

2 Comments

This is the only location where the problem occurs and it feels overkill to include a library on an application that we've been using redux in for several months. We were changing out data structures around while migrating to a MBaaS and ran into this problem, what do you feel would be the best course of action knowing that this is the only use-case? Do you feel that importing a library is necessary, or should serializing/deserializing work fine for this? I have a custom componentShouldUpdate that blocks unecessary renders based on a cache, so that shouldn't be a problem.
I'd say if the app is working and you aren't currently having any performance problems a full re-render doesn't seem like a concern at the moment. Switching to seamless-immutable later is very easy.
0

The spread operator is commonly used to make deep copies of JS objects. When we have nested arrays or nested data in an object, the spread operator makes a deep copy of top-level data and a shallow copy of the nested data. While JSON.parse(JSON.stringify(obj)) will do a deep copy of nested data also.

Comments

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.