What's a closure?
Closures are like a backpack for functions. The backpack holds all of the values the function needs from its original environment, even if it's called in a different place. It gives functions access to all of its belongings no matter where it's called.
Here's a simple code example:
function createCounter(){
let count = 0
return function (){
count++
console.log(count)
}
}
const counter = createCounter()
counter() // Outputs: 1
counter() // Outputs: 2
counter() // Outputs: 3
The inner function has a closure (or backpack) that allows it to "remember" the value of count no matter where we call it!
This is a super powerful tool that makes a lot of things possible!
Closures in React
Here's the "React" version of the above code
export function Counter(){
const [count, setCount] = useState(0)
function updateCount(){
setCount(count + 1);
}
return (
<button onClick={updateCount}>
{count}
</button>
)
}
The closure is what allows updateCount
to remember and access the value of count
and the setCount
function.
React Rendering - a snapshot of the component
export function Counter(){
const [count, setCount] = useState(0)
function updateCount(){
setCount(count + 1);
console.log(count) // what do we get here?
}
return (
<button onClick={updateCount}>
{count}
</button>
)
}
Now what happens when we log the value of count
after updating it?
It may surprise you - but it's still whatever the value was before you updated it! (i.e. 0 after first clicked)
The reason: React doesn't immediately update count
so we are left with a stale value - in this case, what the count originally was before the update.
Instead, count
(state) won't be updated until React renders the component again.
This is because [state behaves like a snapshot](https://react.dev/learn/state-as-a-snapshot)