useCallback
in ReactThe useCallback
hook in React is used to memoize functions so that they are not recreated on every render. This helps in optimizing performance, especially in scenarios where the function is passed as a prop to child components or used in expensive computations.
useCallback
?Every time a component re-renders, all its functions are recreated, even if their logic hasn’t changed. This can lead to:
By memoizing a function with useCallback
, you ensure the function retains its identity unless its dependencies change.
useCallback
Worksconst memoizedCallback = useCallback(() => {
// Your function logic here
}, [dependencies]);
useCallback
returns the same function instance as long as the dependencies don’t change.Here’s an example of how useCallback
can prevent unnecessary re-renders:
<strong>useCallback</strong>
:import React, { useState } from "react";
const Child = React.memo(({ onClick }) => {
console.log("Child rendered");
return <button onClick={onClick}>Click Me</button>;
});
const Parent = () => {
const [count, setCount] = useState(0);
const handleClick = () => {
console.log("Button clicked");
};
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<Child onClick={handleClick} />
</div>
);
};
export default Parent;
Behavior:
Parent
re-renders (when count
changes), the handleClick
function is recreated.Child
component to re-render unnecessarily, even though its props haven’t changed.<strong>useCallback</strong>
:jsx
Copy code
import React, { useState, useCallback } from "react";
const Child = React.memo(({ onClick }) => {
console.log("Child rendered");
return <button onClick={onClick}>Click Me</button>;
});
const Parent = () => {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log("Button clicked");
}, []); // No dependencies, so the function is memoized and won't change
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<Child onClick={handleClick} />
</div>
);
};
export default Parent;
Behavior:
handleClick
function is memoized using useCallback
.Child
component doesn’t re-render unless handleClick
changes, which happens only if its dependencies change (none in this case).When a function depends on state or props, you can include them in the dependency array.
const Parent = () => {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log(`Count: ${count}`);
}, [count]); // Recreate the function only if `count` changes
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={handleClick}>Log Count</button>
</div>
);
};
Behavior:
handleClick
function is recreated only when count
changes, ensuring it always logs the latest value of count
.useCallback
onClick
, onChange
, etc.useCallback
useCallback
. Use it only when there’s a clear performance benefit.useCallback(() => {...}, [dependencies])
Let me know if you’d like a deeper dive or more examples! 🚀
The useCallback hook in React is used to memoize functions so that they are not recreated on every render. This helps in optimising performance, especially in scenarios where the function is passed as a prop to child components or used in expensive computations.
Every time a component re-renders, all its functions are recreated, even if their logic hasn’t changed. This can lead to unnecessary re-renders of child components or performance issues in complex apps. By memoizing a function with useCallback, you ensure the function retains its identity unless its dependencies change.
useCallback returns the same function instance as long as the dependencies don’t change. When dependencies change, a new function is created.
Here’s an example of how useCallback can prevent unnecessary re-renders.
Parent re-renders on the Increment button click.
Every time the Parent re-renders (when count changes), the handleClick function is recreated.
Even though Child is a pure component, this causes the Child component to re-render unnecessarily, as the onClick handler is a new function, albeit doing the same functionality as its previous version.
Therefore we need to make sure that this callback is not recreated unnecessarily.
For this, we apply the useCallback hook and memoise the handleClick function.
When we click the button, the Child component doesn’t re-render unless handleClick changes, which happens only if its dependencies change (none in this case).
When a function depends on state or props, you can include them in the dependency array.
The handleClick function is recreated only when the count changes, ensuring it always logs the latest value of the count.
Clicking on the Increment button re-renders child
But logging displays the correct value. Try removing the count from the dependency variables and guess what happens!
useCallback can help optimise your app. Use it when passing Functions as Props to prevent unnecessary re-renders of memoized child components.
Also, to optimise frequently used handlers like onClick, onChange, etc.
Or to memoize expensive functions that are called repeatedly in the render cycle.
But useCallback comes with small performance overhead and it also makes your code harder to read. Therefore, do not overuse this hook, and don’t wrap every function in useCallback. Use it only when there’s a clear performance benefit.
Remember that in small apps, function recreation is rarely a performance bottleneck.
To summarise ...
The purpose of useCallback is to memoize functions to prevent unnecessary re-creations and improve performance.
The syntax of use callback is defined by the callback function and a list of dependencies defining when to re-create this callback
The key use case is to prevent child re-renders, optimize event handlers, and memoise expensive functions.
But, use it judiciously; overuse can complicate code without significant benefits..