I have set the state to true before calling the setInterval
function. But even though the useEffect
hook is being triggered with the new value of the state, it's not being reflected in the setInterval
function.
Code sandbox here: https://jsfiddle.net/6e05tc2L/3/
let interval;
const Component = () => {
React.useEffect(() => {
console.log('State updated to', state);
});
const [state, setState] = React.useState(false);
const on = () => {
setState(true);
interval = setInterval(() => {
console.log(state);
}, 1000);
}
const off = () => {
setState(false);
clearInterval(interval);
}
const toggle = () => state ? off() : on()
return (<div>
<button onClick={toggle}>Toggle State</button>
</div>);
}
ReactDOM.render(
<Component />,
document.getElementById('container')
);
Shouldn't it be using the newer value of state once it's updated?
setInterval
is created just 1 time whenon
is called, and it closes over the value ofstate
at the time it is created. Future renders callReact.useState
again and "see" a newstate
, but that function created whenon
was called is essentially stuck in the past: it closed overstate
when it was created and will never get a new value ofstate
. – BeliefuseInterval
, it callsuseEffect
on each render and updates a ref's.current
with a new version of the callback that closed over the value ofstate
for that render call. The function passed to the nativesetInterval
never changes, but all that function does is call another function whose reference actually is updating on every render. – Belieftick
never changes, but in your own call ofuseInterval
you are passing in a new function on every render. That function gets set tosavedCallback.current
and called by the permanenttick
. – Belief