How to use React useMemo and useCallback hook
Is it bad to re-initialize local variables, and event functions inside a React functional component?
// Reinitialize variables and functions on every state update
function App() {
const [value, changeValue] = React.useState('');
const [cats, updateCatList] = React.useState([{name: 'Mr. Whiskers'}, {name: 'Fluffy'}]);
const handleSubmit = () => {
// ... some logic and print list
updateCatList([...cats, value]);
};
const handleChange = e => {
// ... Some logic and update state
changeValue(e.target.value);
};
return (
<>
<input onChange={handleChange} />
<button onClick={handleSubmit}>Submit</button>
{JSON.stringify(cats)}
</>
);
}
99% of time, probably not.
But maybe, you’re that 1% that you notice some heavy computation is killing your apps performance.
Or maybe, you just want to pre-optimize.
If those are the cases, let me tell you about why React useMemo
, and useCallback
is useful for your problems, and how it works.
Why React useMemo is useful
This hook creates a memoized value.
Sometimes you have to compute a value through a complex calculation or you have to make a call to a costly database network.
Using React useMemo
will perform the action once, and store the value as a memoized value.
So the next time you reference that local variable, it will get the value quicker.
useMemo(() => callback, array_dep);
Here’s how to use React useMemo
:
const catsValue = React.useMemo(() => highlyCostCatQueryCall());
This hook behaves almost like React useEffect
. In the sense that if you don’t pass an empty array ([]
) as the second parameter, React useMemo
will get triggered on any update.
const catsValue = React.useMemo(() => highlyCostCatQueryCall(), []);
If you’d like to trigger this hook again, add some dependencies in that empty array.
const catsValue = React.useMemo(() => highlyCostCatQueryCall(arg1, arg2), [arg1, arg2]);
If any of those dependencies in the array change in value, then React useMemo
will re-trigger, and save the new value as a memoized value.
Why React useCallback is useful
React useCallback
is similar to useMemo
.
The difference between useCallback
and useMemo
is that useCallback
returns a memoized callback function. And useMemo
returns a memoized value
The objective is to not re-initialize the function or the value, unless it’s array dependencies have changed.
useCallback(func, array_dep);
Here’s how to use React useCallback
:
function App() {
const [counter, setCounter] = React.useState(0);
const [autoCounter, setAutoCounter] = React.useState(0);
const incrementCallback = React.useCallback(() => {
setCounter(counter + 1);
}, [counter]);
React.useEffect(() => {
setInterval(() => {
setAutoCounter(c => c + 1);
}, 1000);
}, []);
return (
<>
<h1>Auto counter: {autoCounter}</h1>
<h2>Manual counter: {counter}</h2>
<button onClick={incrementCallback}>Increment</button>
</>
);
}
In the example above I have 2 different useState
variables, counter
and autoCounter
.
autoCounter
will auto increment every second by 1.
I set that code command inside a setInterval()
within my React useEffect hook
.
const [autoCounter, setAutoCounter] = React.useState(0);
React.useEffect(() => {
setInterval(() => {
setAutoCounter(c => c + 1);
}, 1000);
}, []);
In the example above I also have another React state variable called counter
.
This variable will need to get incremented manually by clicking on the button.
Here’s the click event handler for the button:
const incrementCallback = React.useCallback(() => {
setCounter(counter + 1);
}, [counter]);
Notice how I wrap my callback function inside a React useCallback
hook.
That lets React know to not re-initialize this function, incrementCallback
, every time it re-renders.
I did let it know to only re-initialize, when the counter state variable gets updated.
If I pass an empty array dependency, I can only use the function once.
If I don’t pass a second parameter, incrementCallback
gets re-initialized every time the React component re-renders.
Conclusion
99% of the time you don’t need to use these optimization tools.
And everything comes at a cost. In this case, it comes with more complexity.
But that’s up to you to decide whether it’s worth it or not.
I like to tweet about React and post helpful code snippets. Follow me there if you would like some too!