I'm trying to understand the general advice I've seen regarding React and stale closures.
Specifically, as I understand it, the term "stale closure" is used to describe a scenario where a component and useEffect
function are constructed like this
function WatchCount() {
const [count, setCount] = useState(0);
useEffect(function() {
setInterval(function log() {
console.log(`Count is: ${count}`);
}, 2000);
}, []);
return (
<div>
{count}
<button onClick={() => setCount(count + 1) }>
Increase
</button>
</div>
);
}
React calls WatchCount
to render a component, and sets the value of the count
variable. When javascript calls the log
function two seconds later, the count
variable will be bound to the count
variable from when WatchCount
was first called. The value of count
won't reflect updates that may have happened on renders of WatchCount
that happened in-between the first render and the interval code eventually firing.
The general advice that's given to "solve" this is to list your variable in the dependencies array -- the second argument to useEffect
useEffect(function iWillBeStale() {
setInterval(function log() {
console.log(`Count is: ${count}`);
}, 2000);
}, [count]);
As a javascript programmer, I don't understand how this "solves" the problem. All we've done here is create an array that includes the variable in it, and passed that array to useEffect
My naive view is that the count
variable in log
is still scoped to the first call of WatchCount
, and should still be stale.
Am I missing some nuance of javascript's scope here?
Or does this "fix" things because of something that useEffect
is doing with those variables?
Or some third thing?