useCallback vs useMemo
useCallback and useMemo are both hooks in React that are used to optimize performance by memoizing values. However, they serve different purposes and are used in different ways:
- useCallback is used to memoize functions
- useMemo is used to memoize the result of a function
useCallback
useCallback
is used to memoize functions. It is used to prevent unnecessary re-renders of components. It is used when you have a function that is passed as a prop to a child component and you want to prevent the child component from re-rendering when the function changes.
When to use useCallback
:
- When you pass a function as a prop to a child component that is wrapped in React.memo, you should use useCallback on that function. This prevents the child component from re-rendering unnecessarily because the function prop is a new reference on every parent render.
- When a function is a dependency in another hook like useEffect, it's crucial to wrap it in useCallback to prevent the effect from running on every render.
Basic Syntax:
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
Real World Example:
import React, { useState, useCallback } from 'react';
const ChildComponent = React.memo(({ onClick }) => {
console.log('ChildComponent rendered');
return <button onClick={onClick}>Click me</button>;
});
const ParentComponent = () => {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
setCount(prevCount => prevCount + 1);
}, []); // Empty dependency array means the function is created only once
return (
<div>
<p>Count: {count}</p>
<ChildComponent onClick={handleClick} />
</div>
);
};
Without useCallback
, a new handleClick
function would be created on every render of ParentComponent
, causing ChildComponent
to re-render even though its props haven't conceptually changed.
useMemo
useMemo
invokes a function and returns its memoized result. The function is only re-executed if one of its dependencies has changed.
Basic Syntax:
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
When to use useMemo
:
- Expensive calculations: When you have a computationally intensive function that runs on every render, you can use useMemo to cache its result and only recompute it when necessary.
- Memoizing computed values: When you have a complex value that depends on multiple other values, you can use useMemo to memoize that value and only recompute it when necessary.
Real World Example:
import React, { useState, useMemo } from 'react';
const expensiveCalculation = (num) => {
console.log('Performing expensive calculation...');
// Simulate a heavy computation
for (let i = 0; i < 1_000_000_000; i++) {
// Do something
}
return num * 2;
};
const MyComponent = () => {
const [count, setCount] = useState(0);
const [number, setNumber] = useState(10);
const calculatedValue = useMemo(() => expensiveCalculation(number), [number]);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
<p>Calculated Value: {calculatedValue}</p>
<button onClick={() => setNumber(number + 1)}>Increment Number</button>
</div>
);
};
In this example, the expensiveCalculation
will only run when the number
state changes. Clicking the "Increment Count" button will not trigger the recalculation.
Summary
- Use
useCallback
for functions you want to pass down without causing re-renders. - Use
useMemo
for values you want to memoize and prevent re-computation.