admin管理员组

文章数量:1289402

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 ponent, 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.

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 ponent, 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.

Share Improve this question asked Apr 20, 2017 at 2:26 HobbyistHobbyist 16.2k11 gold badges53 silver badges102 bronze badges 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/docs/basics/Reducers.html) – Wei 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. – ShadowRanger Commented Apr 20, 2017 at 2:45
Add a ment  | 

2 Answers 2

Reset to default 9

react-redux connected ponents do a shallow strict equality check to decide if they want to update. see http://redux.js/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 ponents 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 remend checking out the seamless-immutable or immutable packages for managing state. Also, the reselect library can help you extract memoized objects specific to your ponent's needs.


UPDATE 08/16/2020

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

The spread operator is monly 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.

本文标签: javascriptSpread operator vs JSONparse(JSONstringify()) for immutable objectsStack Overflow