Here's an example:
function Page() {
const [a, setA] = React.useState(0);
useEffect(() => {
const interval = setInterval(() => { console.log(a) }, 2000)
return () => clearInterval(interval)
}, []);
return (
<div>
<span>{a}</span>
<button onClick={() => setA(Math.random())}>button</button>
</div>
);
}
The invertal always log 0 despite the fact that count state variable has actually being increased by clicked the button a few times.
And many people say this is because the interval function capture a. But I really can not undersand it. When a variable can not be found in current environment, it will resolve to parent (or global).
And look at this example in contrast:
function Page() {
let a = 0;
useEffect(() => {
const interval = setInterval(() => { console.log(a) }, 2000)
return () => clearInterval(interval)
}, []);
return (
<div>
<button onClick={() => a = Math.random()}>button</button>
</div>
);
}
This is an obvious example for my expression. The interval closure capture the outer a variable. It will log the fresh value as it changes.
So how react useEffect implement this feature?
As my view (a bad pseudocode):
const hooks = [];
function useState(val) {
let state = hooks[0] || val;
hooks[0] = state;
function setVal(v) {
state = v;
hooks[0] = state;
}
return [state, setVal];
}
let cleanup = null;
function useEffect(callback) {
if (cleanup) cleanup()
cleanup = callback();
}
function Foo() {
const [count, setCount] = useState(0);
useEffect(() => {
setTimeout(() => { console.log(count)}, 1000);
})
return setCount;
}
var setCount = Foo(); // log 0
setCount(1);
Foo(); // log 1
But this is not way react was implement. So how react implement this?