Home > Back-end >  ReactJS useState hook: Can I update array of objects using the state variable itself?
ReactJS useState hook: Can I update array of objects using the state variable itself?

Time:05-07

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 to list.

      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:

  • Related