Reputation: 66
In the following example, when the button is clicked, cb2
uses the memoized function. However, why doesn’t cb2
use the first render closures (countVal: 0
)?
function TestHook() {
const [count, setCount] = useState(0)
let countVal = 0
const cb = useCallback(() => {
console.log('cb dep [count]', count, countVal)
}, [count])
const cb2 = useCallback(() => {
console.log('cb2 dep []', count, countVal)
}, [])
useEffect(() => {
cb() // first time: 0, 0 second time: 1, 0
cb2() // first time: 0, 0 second time: 0, 1
})
const add = () => {
console.log('add', count)
countVal ++
setCount(count + 1)
}
return (
<>
<button onClick={add}>add</button>
</>
);
}
Question:
Can anyone explain the result of cb2()
after a re-render?
Upvotes: 1
Views: 74
Reputation: 29334
why doesn’t cb2 use the first render closures (countVal: 0)?
It is using the countVal
from the first render. Reason you see its value as 1 instead of zero is because clicking the "add" button increments the value of countVal
variable.
After the first click, countVal
from the first render is incremented to 1, so that is what gets logged from cb2()
call on subsequent clicks.
Note on closures:
Functions close over variables, not their values. If you change the value of a variable (countVal
in your example), any function that has a closure over that variable will see its latest value.
Upvotes: 2
Reputation: 704
First render:
Second render (after clicking the button):
Why does cb2() log 0, 1 on the second render?
useCallback([]): Since cb2 has no dependencies ([]), it doesn't recreate the callback after the first render. This means that on the second render, cb2 is still using the closure from the first render, but React captures the updated value of countVal due to how the JavaScript closure works.
Upvotes: 2