Skip to content

Instantly share code, notes, and snippets.

@HuyAms

HuyAms/blog.md Secret

Created November 11, 2019 08:56
Show Gist options
  • Save HuyAms/2894d7cbc4ccc8629c3860ddfe2faeda to your computer and use it in GitHub Desktop.
Save HuyAms/2894d7cbc4ccc8629c3860ddfe2faeda to your computer and use it in GitHub Desktop.

Introduction to React.memo, useMemo and useCallback

Prerequisite: Basic knowledge about React

When I start to write this blog, I ask myself whether I should only talk about the differences between useMemo and useCallback because they are React Hooks while React.memo is not. Eventually, I decided to include React.memo as well since on the one hand the word memo in both terminologies might sound a bit confusing for people. On the other hand, it's all about React optimization ๐Ÿ˜

optimization

1. What is React.memo

If you are familiar with React.PureComponent then React.memo is quite straightforward as it is exactly similar to React.PureComponent. We use React.PureComponent with class component while React.memo works with functional components ๐Ÿ‘Œ

Let's take a look at our example to see how it works. Codesandbox

Note: All the examples below are used only to express the main ideas. In reality, we don't need optimization in such simple cases

https://gist.github.com/6c6ff79ccb75ce5cf38742a91e17372d

https://gist.github.com/d4771e70f1f27cfbca9e1fa99ce655b3

Every time the user clicks on the button, the state of count1 changes causing the App to rerender both counters which is known as unnecessary re-render. However, we expect only the counter1 to be rerendered since nothing has changed with the counter2. In reality, both counters get rerendered.

How can we address this issue? ๐Ÿค” Well, React.memo is our answer. All we need to do is to wrap our Counter component within React.memo

https://gist.github.com/2624f68105595e4042b83f3b20f12d5d

By default, React.memo will compare all props passed to the component by referential equality. If these props are unchanged, React.memo will reuse the last rendered result, therefore, it prevents the component from being rerendered. In our example, React.memo will check if there are any changes with the value and children props since the last render. Since our button only changes the value of the counter1, React.memo will prevent the counter2 from being rerendered. ๐Ÿ˜Ž๐Ÿ’ช

We can also override the default comparison of React.memo by providing a custom comparison function as the second argument.

From React.memo documentation https://gist.github.com/88103f2d81b0a4d579e37ad00ed94925

2. useMemo and useCallback

I will start with the documentation

useMemo returns a memoized value https://gist.github.com/c68e4983bc9870bab3815e154cb7f56f

useCallback returns a memoized callback https://gist.github.com/41b146ad28dd544215b10794a0e8200c

๐Ÿ’ช Let's break it down together

Both React.useMemo and React.useCallback receives a function as its first argument and a dependencies array as the second one. The hook will return a new value only when one of the dependencies value changes (referential equality). The main difference is that React.useMemo will call the fooFunction and return its result while React.useCallback will return the fooFunction without calling it.

๐Ÿ˜ซ Example please codesandbox

https://gist.github.com/744686913e5b63abeaf65715d27e60ba

If you run the code and take a look at your console, not refrigerator, you can see the following output

use-memo-and-callback-result

React.useMemo runs the fooFunction which returns a string Foo is just Food without D while React.useCallback just returns a fooFunction without calling it

๐Ÿคฉ Got it. But how does it work in React?

๐Ÿ€ useMemo

Normally we could use React.useMemo when we compute expensive value that we don't want to compute it again and again when the component is rerendered

https://gist.github.com/92825778ad0a1f6cdaf542311758f687

Imagine that it takes full of my energy to calculate myReply value and what if I have to do it again and again (recalculate) when my girl friend says something (rerender) ๐Ÿค

๐Ÿ”ฅ React.useMemo comes to rescue

https://gist.github.com/ae7b3ea86b31472d5a55852616961aa2

Thanks to React.useMemo, I couldn't have finished this blog without you ๐Ÿ’‘

React.useMemo takes [girlFriendWords] as its dependencies array which means that it will only run decideWhatToSay function when girlFriendWords value changes. I don't have to think twice to reply when my girlfriend says the same thing. Optimization here ๐ŸŽ‰๐Ÿ€๐Ÿ’

girlfriend-optimization

๐Ÿ€ useCallback

Enough relationship story, let's get back to our Counter example. Let's tweak the example a little bit, our counter now also receives onClick function as a prop. Could you guess whether our Counter2 component will be rerendered when count1 value change

https://gist.github.com/0a66178ed30c408f867ab1c4b0c14aa7

https://gist.github.com/5c081d5cb3f92c03fe47965723b6b462

The answer is YES ๐Ÿ˜ฎ.

Even when we use React.memo, the counter2 component is still rerendered when only the count1 changes because React.memo uses reference equality to prevent unnecessary renders. However, when App is rerendered, the increaseCounter2 is recreated, therefore, the onClick props passed into the Counter component is different every time which causes the component to be rerendered. The easy way to avoid this issue is to prevent the increaseCounter2 function from being recreated when the App is rerendered.

We make use of React.useCallback to do this

https://gist.github.com/830531272f163d08f5508193730fed31

Take a look at the dependencies array, it's empty because I want to create these functions only once. In this way, the onClick props passed to the Counter component is always the same

3. Conclusion:

  • ๐Ÿš€ We should not optimize unnecessary rerenders without measuring the cost first. Optimization always comes with a cost
  • ๐Ÿš€ React.memo is similar to React.PureComponent except the fact that it is used for functional component while React.PureComponent is used only in class component
  • ๐Ÿš€ React.useMemo returns a memoized value while React.useCallback return a memoized callback

Here are some good resources for you:

๐Ÿ™ ๐Ÿ’ช Thanks for reading!

I would love to hear your ideas and feedback. Feel free to comment below!

โœ๏ธ Written by

Huy Trinh ๐Ÿ”ฅ ๐ŸŽฉ โ™ฅ๏ธ โ™ ๏ธ โ™ฆ๏ธ โ™ฃ๏ธ ๐Ÿค“

Software developer | Magic lover

Say Hello ๐Ÿ‘‹ on

โœ… Github

โœ… LinkedIn

โœ… Medium

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment