Home > Software design >  Why do I need to spread the array if set a new value with a useState hook?
Why do I need to spread the array if set a new value with a useState hook?

Time:02-04

I have an array and on click event, it will be randomized. If I use just prev.sort((a, b) => 0.5 - Math.random()) at the return, well, it will be updated, but the child element (Hive) which receives the array as a prop, won't re-render, but if I return it as [...prev.sort((a, b) => 0.5 - Math.random())] then the child element will re-render. Can you tell me why is that? Am I doing something wrong?

const actualLetters = ['b', 'i', 'p', 'r', 'e', 't', 'y'];

  const [randomizedLetters, setRandomizedLetters] = useState(
    actualLetters.slice(1).sort((a, b) => 0.5 - Math.random())
  );

  const randomevent = () => {
    setRandomizedLetters((prev) => {
      console.log(prev);
      //doesn't work
      //return prev.sort((a, b) => 0.5 - Math.random());
      //it works
      return [...prev.sort((a, b) => 0.5 - Math.random())];
    });
  };

  return (
    <main>
      <Hive actualLetters={randomizedLetters} letterCenter={actualLetters[0]} />
      <div className='buttonsContainer'>
        <Button title='Delete' clickEvent={deleteEvent} />
        <Button className='circle' title={<SlRefresh />} clickEvent={randomevent} />
        <Button title='Enter' clickEvent={enterEvent} />
      </div>
    </main>
  );

CodePudding user response:

React operates on the assumption that state is immutable. With this assumption it's very easy for react to check if the state has changed: just do an === between the old and new state1. .sort mutates the array, so it breaks this assumption. React does an === between the old and new states, sees that they're the same array, and so it thinks that nothing has changed. Since nothing has changed it skips rendering.

When you copy the array and sort the copy, you now have a new array. React notices that it's a new array, and thus rerenders.

1) technically uses the Object.is logic for the comparison instead of ===, but similar idea

CodePudding user response:

The sort method mutates the array, and when you set the sorted array (without spread), react doesn't register the change because it's the same array. Spreading the array creates a shallow clone that react can identify as a change.

However, you are still mutating the original array. First spread, and then sort:

[...prev].sort((a, b) => 0.5 - Math.random())
  • Related