0

I always thought using React, we can use

data.payload.records[0].someField = "abcd1234";
setData({...data});

and it would trigger a re-render of the correct table values.

The data and setData is by

const [data, setData] = useState(null);

and the API will fill in the data.

But to my surprise, the above would not update the table values. If I use a deep copy such as lodash's _.cloneDeep() to clone data, then it would update the table's values.

So for experiment 2, I used

const payloadNew = deepCopy(payload);
payloadNew.records[0].someField = "abcd1234";
setData({...data, payload: payloadNew });

and it works too.

As experiment 3, I used

data.payload.records[0] = deepCopy(data.payload.records[0]);
data.payload.records[0].someField = "abcd1234";
setData({...data});

and it works too.

So

  1. What is the rule? What is the reason it works sometimes and sometimes not? Could it be due to sometimes, the code is written so that data.payload is passed down to the table component, so it is the same payload object, and React optimized it by skipping over the whole table component re-render? So since we don't know what is passed down (such as data.payload or data.payload.records (other programmers can change it too), so we really should make a deep copy of everything).
  2. Should we always make a deep copy from the top most level so that there is no unexpected result?

The reason I may not want to make a deep copy every time is that, what if there are 1000, 2000, 5000 items, or more, so making a deep copy every time can make the UI sluggish. And if one value is changed, we need to make a copy of 25,000 values? (assuming 50 properties per item). That may sound too mind boggling. However, if it is the world of Redux, I think they always make everything a new object by deep copy.

Stefanie Gauss
  • 425
  • 3
  • 9
  • When the state if updated, you must create a new state. React state should be immutable. There is a library that Redux uses called Immer that makes it easy to mutate an existing state in an immutable way. – Mr. Polywhirl May 30 '23 at 19:17
  • When calling `setData`, you should grab the current value of `data` using the function version. Never call `data` when also calling `setData`, because this can cause an infinite loop. Instead call, `setData(currentData => { /* return modified currentData */ })` See also: [How to update nested state properties in React](https://stackoverflow.com/questions/43040721/how-to-update-nested-state-properties-in-react). Specifically [this answer](https://stackoverflow.com/a/52001646/1762224). – Mr. Polywhirl May 30 '23 at 19:24
  • so when you say immutable, that means you create a brand new object, and that is exactly what deep copy or deep clone is about. I guess I can use immer but that should be the same principle of a deep copy – Stefanie Gauss May 31 '23 at 08:16
  • Well, for one: [Immer eliminates accidental mutations](https://news.ycombinator.com/item?id=26386763) and it's much easier to tell what's being updated. – Mr. Polywhirl May 31 '23 at 12:58

0 Answers0