I know how closures work but I'm failed to understand how a stale closure gets create in a React's useEffect in the absence of an exhaustive dependencies array. To do so, I'm trying to replicate a stale closure just like in React's useEffect without using the useEffect, but I'm unable to create it. My code doesn't create a stale closure and instead logs a correct value on every interval. Could you please take a look at the snippet below and tell me:
What am I doing wrong? What should I do to create a stale closure like the one we get in React's
useEffectwhen we don't provide the complete dependencies array? (reference code is at the end of the post)Why does a stale closure is created when we don't give exhaustive dependencies in a useEffect? Why doesn't the code in a
useEffecthook's callback just use the lexical scope, like a normal function would, and print the actual value?
function createIncrement(incBy) {
let value = 0;
function increment() {
value += incBy;
console.log(value);
}
function useEffect(fun) {
fun()
}
useEffect(function() {
setInterval(function log() {
// what should I do to create a stale closure here?
// So that if I change the value it should show me the old value
// as it does when using React's useEffect without exhaustive dependencies array
console.log(`Count is: ${value}`); // prints correct value each time
}, 2000);
});
setTimeout(() => {
increment(); // increments to 5
increment(); // increments to 6
}, 5000);
return [increment];
}
const [increment] = createIncrement(1);
increment(); // increments to 1
increment(); // increments to 2
increment(); // increments to 3
increment(); // increments to 4
For completeness sake, below is a code snippet using React's useEffect where we don't provide an exhaustive dependency array to React's useEffect and hence a stale closure is created:
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function WatchCount() {
const [count, setCount] = useState(0);
useEffect(function () {
setInterval(function log() {
// No matter how many times you increase the counter
// by pressing the button below,
// this will always log count as 0
console.log(`Count is: ${count}`);
}, 2000);
}, []);
return (
<div>
{count}
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<WatchCount />, rootElement);