Optimise React App Performance Using useMemo() and useCallback() Hooks Wisely.

Ajin Kabeer
The Startup
Published in
4 min readSep 4, 2020

Learn how to optimise your React app performance by using the useMemo() and useCallback() hooks correctly and also learn when to use the React.memo function.

Unsplash

Did you know that React offers a function called React.memo to optimise performance? And also, did you know that React offers hooks called useCallback() and useMemo() which again can optimise the app performance?. Are you confused about when to use which technique? I will explain the most common use-cases of these techniques with a simple example so that you can learn and ship highly performant react applications in the future.

React.memo

React.memo is a Higher Order Component. You can wrap your component with React.memo(<Component />) for a performance boost by memoising the result of the component.

Here is a simple example.

ParentComponent.js
ChildComponent.js
React app on codesandbox

If you look closely, every single time we click the Up button to increment the local state, our child component re-renders, which is unnecessary as the prop passed down to the child component never changes.

We can use the React.memo function to memoise the child component to avoid this un-necessary re-render. React.memo is a HOC, which will only re-render the component if the props change.

Memoized ChildComponent.js
React app on codesandbox

useCallback() Hook

The useCallback() hook returns a memoized callback.

To learn how to use this hook, we first need to break the memoized component we created above.

Michael Scott has no idea, neither do I.
ParentComponent.js

I’ve passed the incrementChildState function as a prop to the child component.

ChildComponent.js

Let’s now look at how it works.

React app on codesandbox

So we are back to square one. Our React.memo is not working anymore, and the child component re-renders again if even if we are only incrementing the state in the parent component.

useCallback() hook to the rescue :)

But before we jump in, we need to understand the concept of referential equality in JavaScript.

Here is a super-informative article written by Dmitri Pavlutin which clearly explains the concept of referential equality.

So basically, defining referential equality in our context is on every single render we are creating an entirely brand new incrementChildState function.

So our child component which is wrapped inside a React.memo HOC does a referential equality check and see’s that the setNumber prop changes on every render cycle, hence the memoized function re-render.

ParentComponent.js

The useCallback() hook accepts two arguments and then returns a new function. The first argument is the function that we need to memoize and the second argument is a dependency array which is similar to the useEffect() hook’s dependency array, we never want the function to change, so we pass in an empty dependency array.

With this change, the memoizedCallback function will stay the same referentially.

React app on codesandbox

useMemo() Hook

useMemo will only recompute the memoized value when one of the dependencies has changed. This optimization helps to avoid expensive calculations on every render.

Let’s take an example where we compute the largest value in an array and render it.

ParentComponent.js
React app on codesandbox

Every time we try to increment the child component state, we are computing the largest number in the array which is really inefficient and expensive computation.

useMemo() hook will accept a function as an argument, and cache the function until the arguments the function depends on actually changes.

React app on codesandbox

Congratulations ⚡

If you manage to reach this far, then I hope you have learned something about useCallback(), useMemo and React.memo.

My twitter handle is @kabeerajin

Thank you!

--

--