Can the React useMemo() Hook Be Used for Memoizing Functions?

You can memoize/cache functions using the React useMemo() hook. To do so, you must return a function from the useMemo() callback, for example, like so:

const foo = useMemo(() => {
  return () => {
    // ...
  }
}, [/* ... */]);

However, you can achieve the same thing with the useCallback() hook, which is designed for memoizing functions:

const foo = useCallback(() => {
  // ...
}, [/* ... */]);

The only difference between using useCallback() instead of useMemo() is that it helps you avoid having to write an extra nested function. Other than that, they're both functionally equivalent. This means that you can use either of the above to memoize function declarations (i.e. function() {}) and function expressions (i.e. () => {}) in a React component.

Please note that memoizing functions is only useful when passing a function as a prop to a memoized component, or to the dependency array of a hook.

For example, consider the following component that has a reactive value used for storing the selected state of "Dark mode":

import React, { useState, useEffect } from 'react';

const App = () => {
  const [isDark, setIsDark] = useState(false);

  const foo = () => {
    console.log('foo was called');
  };

  useEffect(() => {
    foo();
  }, [foo]);

  return (
    <label>
      <input
        type="checkbox"
        checked={isDark}
        onChange={(e) => setIsDark(e.target.checked)}
      />
      Dark mode
    </label>
  );
};

export default App;

In this example, everytime you toggle "Dark mode", it will trigger a re-render, causing the "foo()" function to be recreated. When this happens, the useEffect() callback is executed because React sees a different "foo()" function (as it's reference in memory changes).

One of the ways to fix this issue is to simply wrap "foo()" with useCallback():

const foo = useCallback(() => {
  console.log('foo was called');
}, []);

This is the same as wrapping the function with useMemo() hook in the following way:

const foo = useMemo(() => {
  return () => {
    console.log('foo was called');
  }
}, []);

Please note that when you use useMemo() or useCallback() to memoize a function, it doesn't actually prevent the function from being recreated. Instead, it creates a cached version of the function and returns it if the dependencies haven't changed since the last time the function was called. This can help improve performance because React doesn't have to re-run the function every time the component re-renders, as long as the dependencies haven't changed.


This post was published by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.