When accessing the current state inside a React Hook's setState() call, is the prevState variable a copy or a direct reference to the state object?

Viewed 50

Imagine that we need to update some property inside a object in state. Also we need to keep other properties intact.

const [myState,setMyState] = React.useState({propA: 'FOO'})

I usually do something like this:

function update() {
  setMyState((prevState) => {
    // IS 'prevState' A SHALLOW COPY OR A DIRECT REFERENCE TO THE SAME OBJECT
  });
}

QUESTION

Is prevState a shallow copy or a direct reference to the same object? If it's a direct reference, is basically the very same object, right?

1 Answers

As you can see from the snippet below prevState IS a direct reference to the current state object. In other words, since objects are basically references, prevState is the very same object as the current state.

You can see that behavior in the snippet below:

Note: See that when you update the state without shallow copying the state, you change the state object, but you don't trigger a re-render, because react only checks the object reference, and that remains the same, because you return the very same object, with the very same reference to it.

function App() {
  
  const[myState,setMyState] = React.useState({propA: 'FOO'});
  
  function handleClick() {
    console.clear();
    setMyState((prevState) => {
      console.log('myState: ' + JSON.stringify(myState));
      console.log('prevState: ' + JSON.stringify(prevState));
      console.log('Are "myState" and "prevState" the very same object: ' + JSON.stringify(prevState === myState));
      const shallowCopy = {...prevState}
      console.log('shallowCopy of prevState: ' + JSON.stringify(shallowCopy));
      console.log('Are "shallowCopy" and "prevState" the very same object: ' + JSON.stringify(shallowCopy === myState));
      return prevState;
    });
  }
  
  function updateWithShallowCopy() {
    setMyState((prevState)=>{
      const shallowCopy = {...prevState};
      shallowCopy.propA = 'BAR<-------------------------------------';
      return shallowCopy;
    });
  }
  
  function updateWithoutShallowCopy() {
    setMyState((prevState)=>{
      prevState.propA = 'BAR';
      return prevState;
    });
  }
  
  return(
    <React.Fragment>
      <div>{myState.propA}</div>
      <button onClick={handleClick}>Click to inspect</button>
      <button onClick={updateWithoutShallowCopy}>Update WITHOUT shallow copy</button>
      <button onClick={handleClick}>Click to inspect</button>
      <button onClick={updateWithShallowCopy}>Update WITH shallow copy</button>
      <div>Click in all buttons in order from left to right</div>
    </React.Fragment>
  );
}


ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

Related