Reputation: 3152
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?
Upvotes: 6
Views: 2004
Reputation: 31395
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.
Upvotes: 1
Reputation: 864
I think re-rendering
of component is the reason behind this. can you please post the component hierarchy?
Also try this:
const [obj, setobj] = useState(() => generateInitialObj());
here is a working example: https://stackblitz.com/edit/react-mysrjp
Upvotes: 0
Reputation: 54593
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());
Upvotes: 13