What are the React useMemo and useCallback?

February 10th, 2023
Share:
What are the React useMemo and useCallback?

If you develop with React, you have probably come across the hooks such as useMemo and useCallback. Both of them sometimes look tricky and unclear, especially if you are new to React. But don`t worry! This article will explain why they are needed and how to use them properly.

What are useMemo and useCallback used for?

useMemo and useCallback are hooks used for the performance optimization of React applications. Both work on the memoization principle, which allows storing computation results in a cache and getting the same information whenever needed instead of simply computing it again.

In other words, these two hooks can prevent re-renders and make the code more effective. But don`t rush to use them in every part of your code. In the article below, we will explore in which cases they can be used and in which not.

Usage of useMemo in React

const getFilteredData = (data) =>
data
?.map((item) => ({ id: item.id, value: item.value }))
?.filter((item) => !!item.value);
const Component = ({ items }) => {
// Without useMemo
const data = getFilteredData(items);
// With useMemo
const data = useMemo(() => getFilteredData(items), [items]);
};
  • Without useMemo, the getFilteredData re-runs on every re-render.
  • With useMemo, the getFilteredData returns the same result between renders until the items dependency updates.

Dependencies can be props or a component's state and include values used inside a function. Using any number of dependencies in the array like so [dependecy1, dependecy2,...] is possible.

Usage of useCallback in React

// Without useCallback
const handleClick = () => {};
// With useCallback
const handleClick = useCallback(() => {}, [dependency1]);
  • Without useCallback, the handleClick creates a new function instance on every re-render.
  • With useCallback, the handleClick keeps the same reference on a function between renders until the dependency1 updates. As in the case of useMemo, dependencies can be props or a component's state.

How does the useMemo and useCallback work?

  • On the initial render:
    • useMemo returns the calculation/transformation result.
    • useCallback returns the function instance.
  • In subsequent renders, React compares dependencies with those from the previous render.
  • If any dependency is updated:
    • useMemo returns a new result.
    • useCallback returns a new function instance.

As you may have noticed, both hooks work roughly the same, but there is one significant difference:

  • useMemo keeps the same result between component renders until one of its dependencies updates (returns a memoized value).
  • useCallback keeps the same function instance between component renders until one of its dependencies updates (returns a memoized function).

If the dependency array is not specified as a second parameter, useMemo and useCallback will return a new result, or function instance, on every component render.

Do we need to wrap each function in useMemo and useCallback hooks?

The answer is no! Because React is already a well-optimized library, and most operations are very fast. Additionally, the constant use of useMemo and useCallback takes more memory from memorizing the values of each function. And it also reduces the readability of code.

If your component doesn`t contain complex calculations or expensive transformations, using useMemo and useCallback is unnecessary. But if you see that a component re-render is slow, you might consider using memoization in this case.

When to use useMemo and useCallback?

There are several cases where the use of memoization can be helpful.

Cases where the use of the useMemo is justified:

  • If you have complex calculations or make expensive transformations of the object or array.

  • If you want to optimize the performance of a child component and prevent it from unnecessary re-renders by passing the memoized value as a prop to a child component.

    When a component re-renders, all of its children are re-renders as well. And if one of the child components contains expensive calculations that slow the rendering, we can re-render this component only if its props update by wrapping it into React.memo(). It will help avoid rendering a child component when its parent re-renders and props are not updated.

    const ChildComponent = ({ data }) => { return (...); }
    const MemoizedChildComponent = React.memo(ChildComponent);
    const Component = ({ items }) => {
    const data = useMemo(() => getFilteredData(items), [items]);
    return (
    <MemoizedChildComponent data={data}>
    );
    };

    But if you wrap a child component into React.memo() and forget to wrap its props into the useMemo, the optimization won`t work because every time, the getFilteredData function from the example above will return a new result. That means the data prop in the Child Component will constantly change, and the component will be re-render.

    That is why useMemo is helpful in this case because it helps to keep the same result between re-renders until one of its dependencies updates.

Cases where the use of the useCallback is justified:

  • You pass the memoized function as a prop to a memoized child component, as in the case of useMemo (see the description above).
const ChildComponent = ({ onSubmit }) => { return (...); }
const MemoizedChildComponent = React.memo(ChildComponent);
const Component = ({ items }) => {
const handleSubmit = useCallback(() => { ...submit logic }, [dependency]);
return (
<MemoizedChildComponent onSubmit={handleSubmit}>
);
};
  • If the function is a dependency of useEffect or another hook. One of the common examples is fetching the API data.
const fetchData = useCallback(async () => {
try {
const result = await apiCall();
console.log(result);
} catch (error) {
console.log(error);
}
}, []);
useEffect(() => {
fetchData();
}, [fetchData])
  • If you use an external function or hook.
const externalHandler = useCallback(
externalFunction(param)
, []);

Conclusion

useMemo and useCallback are nice hooks for optimization, but both can be useful as well as harmful. Using them in each function can lead to slower applications and make the code less readable and more amateur. However, reasonable usage of these hooks can increase the performance of your application.

We hope this article was helpful to you! Thanks for reading!

Subscribe icon

Subscribe to our Newsletter

Sign up with your email address to receive latest posts and updates