useCallback vs useMemo

Jan Hesters
5 min readMay 28, 2019

--

What is the difference between useCallBack and useMemo? And why do useMemo and useCallback expect a function? If you’ve worked with React Hooks, you might have asked yourself these questions.

We will take a look at how they are distinct from another.

What is the difference between useCallback and useMemo? 🤔

Note: This article was first posted on my blog. I publish each article two weeks later on Medium. You might want to subscribe to my newsletter because you will get content like this earlier! 💌

Another note: This article assumes a basic understanding of Hooks. You should have read “Hooks at a Glance.”.

Abstract

The React docs say that useCallback:

Returns a memoized callback.

And that useMemo:

Returns a memoized value.

In other words, useCallback gives you referential equality between renders for functions. And useMemo gives you referential equality between renders for values.

useCallback and useMemo both expect a function and an array of dependencies. The difference is that useCallback returns its function when the dependencies change while useMemo calls its function and returns the result.

Since JavaScript has first-class functions, useCallback(fn, deps) is equivalent to useMemo(() => fn, deps).

Translation

Let’s understand and explain the abstract description above using simple examples. I’ll go over everything, but feel free to skip what you already know.

First-class functions

We said that in JavaScript functions are first-class. This means in JavaScript you can assign a function to a value.

Storing functions in variables enables you to use them as (the cursive points are important for React Hooks):

  • arguments to other functions,
  • return values from functions,
  • values to an object’s keys,
  • values in an array,
  • even as keys to the Map object.

Functions that return functions or take functions as input are called Higher-Order Functions.

Referential equality

If you use JavaScript, you probably know that there are two equality comparison operators. == for abstract equality and === for strict equality. JavaScript’s equality can be weird, and there are many great articles already written about this topic. Go read those for an in-depth look as I will only cover the basic cases relevant for useCallback and useMemo.

Referential equality uses strict equality comparison which is true if the operands are of the same type and the contents match.

Notice how foo === sameFoo returns false (contrary to greeting === otherGreeting). This is because

  1. two distinct objects are never equal for either strict or abstract comparisons,
  2. an expression comparing objects is only true if the operands reference the same object,
  3. and functions are objects in JavaScript.

foo and sameFoo have the same definition but reference two different objects.

Memoization

Memoization is a way to speed up performance by cutting down on computations.

When you first calculate a result, you save it. If you need the result for the same arguments again, you use the saved one instead of recalculating.

Here is a simple memoize function in JavaScript.

In the example above, you save the result of adding 2 and 3. For each call after the first, the cached result is used.

API

The APIs of useCallback and useMemo look similar. They both take in a function and an array of dependencies.

useCallback(fn, deps);
useMemo(fn, deps);

So what is the difference? useCallback returns its function uncalled so you can call it later, while useMemo calls its function and returns the result.

Side note: Now - knowing about first class functions - you should understand why useCallback(fn, deps) is equivalent to useMemo(() => fn, deps).

In the real world, the examples above are meaningless. I just gave it to help you understand the API. If you can pass a function to useCallback or useMemodirectly and you can use that function with empty dependencies, you could define the function outside of the component (and do without useCallback or useMemo). Therefore, in the real world, you will see something like this.

useCallback usually takes in an inline callback that calls the function that uses the dependencies. And useMemo takes in a “create function” that calls some function and returns its results.

Another side note: The following might be trivial for you, but I had to think about it a long time to get it. The following code is wrong. You can’t use useCallback to memoize values. Meaning useCallback(fn(), deps) isn’t a thing.

Whenever you change name sum recalculates. useCallback and useMemo are so useful because they allow lazy evaluation. result is evaluated eagerly on every render. Try it out and take a look at your console.

So why do we need two Hooks dedicated to memoizing values?

Usage

You want to use useCallback or useMemo whenever you depend on referential equality between renders. I find myself mostly using it for useEffect, React.memo and useMemo to replace shouldComponentUpdate from React.PureComponent because the dependencies of these Hooks get checked for referential equality.

Let’s say you have a component that given a userId displays the user’s data.

Can you spot the mistake(s)?

If you have eslint-plugin-react-hooks installed, it will yell at you for omitting fetchUser from useEffect’s dependencies. But mindlessly adding it will actually create an infinite loop!

In React functions defined in function components get re-created on every render because of closure, which results in referential inequality.

There are two ways to solve this issue. Admittedly the most elegant would be to move fetchUser inside useEffect and add userId as a dependency.

But, this is an article about useCallback and useMemo, so let’s solve the problem using the former. (And, maybe you would like to use fetchUserfunction in multiple places.)

You can define fetchUser with useCallback so that the function stays the same, unless userId changes.

And lastly, let’s say you filter all users and display them in a list.

This is inefficient. We can use useMemo to only recalculate the filtered users, when the query changes.

Summary

  • With useCallback you can define a function that has referential equality between renders.
  • You can use useMemo to calculate a value that has referential equality between renders.

Both only change their return value when their dependencies change.

If you liked this article, you might want to clap for it because it would help me out a lot. Thank you! 🤗

Note: This article was first posted on my blog. I publish each article two weeks later on Medium. You might want to subscribe to my newsletter because you will get content like this earlier! 💌

--

--