I have:
const [list, setList] = useState([]);
Somewhere in the component, I want to do:
list[index][someKey] = some_updated_value;
setList(list);
Is this valid?
Or, is it better to do:
const newList = list;
newList[index][someKey] = some_updated_value;
setList(newList);
If this is better, Why?
CodePudding user response:
I could be wrong but I think either way is mutating the state directly. I think it would be better to do like:
setList(list.map((item,i)=>{
if(index === i){
return {...item, [someKey]: some_update_value};
}
return item;
}))
CodePudding user response:
Both implementations would be considered state mutations and should be avoided as this is anti-pattern in React. React uses shallow reference equality checks as part of its Reconciliation process, i.e. if a chunk of state is the same object reference as the previous render cycle it's assumed the value is the same and rerendering is skipped.
Version 1
This is just directly mutating the state object.
list[index][someKey] = some_updated_value; // <-- mutation! setList(list);
Version 2
This also directly mutates the state object since
newList
is a reference tolist
.const newList = list; // <-- newList reference to state newList[index][someKey] = some_updated_value; // <-- mutation! setList(newList);
The idea with React state updates is to apply the Immutable Update Pattern. This is where you create shallow copies of any state and nested state that is being updated. This is also usually combined with functional state updates where you pass a callback function to the updater function that is passed the previous state to update from. This helps avoid stale state enclosures.
Example:
setList(list => list.map((item, i) => // Array.protptype.map creates new array
i === index
? { // new object reference for updated item
...item, // shallow copy previous item state
[someKey]: newValue // overwrite property being updated
}
: item
));
Good docs:
- Immutable Update Pattern - this is a Redux doc but provides a fantastic explanation and example.
- Functional State Updates