Solving React useCallback hook question
March 19, 2024 2:16 PM
If you see the below code, we know that this is a React Component that is rendering a button having a count value, but the count must increase with every click of the button but there is a bug making it increment only one time.
Let's say we want to fix this issue but if you see the console I am trying to print the value of count and x. When I click on the button every time, the count shows 0 and x is getting incremented.
Let's fix the issue first:
We know that the value of the count is 0 inside the increment function, but we also know that setCount is derived from useState hook which we get to update the state value. Apart from passing value to setCount function, we can also pass a function, This function will get the current state (or you can think as its previous state value)
const increment = React.useCallback( () => { console.log('count', count) console.log('x', x); x++ return setCount(prev => prev + 1); }, [] // add count to the dependency array);
This is how our issue gets solved, now we can reflect the latest state value (count) in the button(UI)
But here we have something more to understand, If you see the console, every time I click the button, the count is 0 and x is getting incremented by 1. So the question is why the latest count value is not logged on the screen where as x shows the latest value.
In JavaScript, a closure is created every time a function is created, at function creation time. The closure gives you access to the scope that was in effect when the function was created.
In your increment function, you're using the React.useCallback hook, which creates a memoized version of the function. The second argument to useCallback is an array of dependencies. The function will only be recreated if the dependencies change.
In your case, the dependency array is empty ([]), which means the increment function is only created once, when the component is first rendered. At that time, count is 0, so every time you call increment, it logs the count that it "remembers" from when it was first created, which is 0.
On the other hand, x is a variable outside of your component. It's not part of any closure and it's not part of React's state management, so it behaves like a regular JavaScript variable. Every time increment is called, x is incremented and the updated value is logged.
If you want increment to log the updated count value, you need to add count to the dependency array of useCallback:
constincrement = React.useCallback(
() => {
console.log('count', count)
console.log('x', x);
x++
returnsetCount(prev=>prev + 1);
},
[count] // add count to the dependency array
);
Now, increment will be recreated every time count changes, so it will always log the current count value.
Comments