Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is useState hook calling initialising value code twice?

Say we have the following code:

const [obj, setobj] = useState(generateInitialObj());

Why it happens that generateInitialObj() is being called twice? I've added logging to generateInitialObj() and I've just noticed it. It seems to be happening at the very begining of the component's life cycle. I though, that once react obtains a value from there, it's gonna remain in there for good. No need to re-obtain it. Any ideas?

like image 354
Patryk Avatar asked Aug 31 '26 07:08

Patryk


2 Answers

It's a JavaScript technicality. There's nothing React can do to prevent generateInitialObj from being called on every single render. To account for this, React supports the following API instead:

const [obj, setobj] = useState(() => generateInitialObj());
like image 137
August Lilleaas Avatar answered Sep 02 '26 23:09

August Lilleaas


Just tested and confirmed that if you use a function call getInitialState(), it will be called everytime, because it is, indeed, normal JS behavior.

function getInitialState() {
  console.log('Executing getInitialState...');
  return({
    propA: 'foo',
    propB: 'bar'
  });
}

function App() {
  console.log('Rendering App...');
  const [myState,setMyState] = React.useState(getInitialState());
  const [myBoolean,setMyBoolean] = React.useState(false);
  
  function updateApp() {
    setMyBoolean((prevState) => !prevState);
  }
  
  function changeAppState() {
    setMyState({
      propA: 'foo2',
      propB: 'bar2'
    });
  }
  
  return(
    <React.Fragment>
      <div>myState.propA: {myState.propA}</div>
      <div>myState.propB: {myState.propB}</div>
      <button onClick={updateApp}>Update App</button>
      <button onClick={changeAppState}>Change App State</button>
    </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"/>

But if you use a function declaration ()=>getInitialState() instead, it will only be called once.

function getInitialState() {
  console.log('Executing getInitialState...');
  return({
    propA: 'foo',
    propB: 'bar'
  });
}

function App() {
  console.log('Rendering App...');
  const [myState,setMyState] = React.useState(()=>getInitialState());
  const [myBoolean,setMyBoolean] = React.useState(false);
  
  function updateApp() {
    setMyBoolean((prevState) => !prevState);
  }
  
  function changeAppState() {
    setMyState({
      propA: 'foo2',
      propB: 'bar2'
    });
  }
  
  return(
    <React.Fragment>
      <div>myState.propA: {myState.propA}</div>
      <div>myState.propB: {myState.propB}</div>
      <button onClick={updateApp}>Update App</button>
      <button onClick={changeAppState}>Change App State</button>
    </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"/>

Other than that, both works just the same.

like image 25
cbdeveloper Avatar answered Sep 02 '26 22:09

cbdeveloper