React useMemo Vs useCallback

Dead Simple Chat Team

Table of Contents

In this article we will explore the differences between React useMemo and useCallback hooks

If you are looking for a React Native Chat SDK to build in app chat messaging application, you can consider DeadSimpleChat React Native SDK

Core Difference

  1. useMemo : Returns a memorized value
  2. useCallback : Returns a memorized function

Let us delve deeper into this

useMemo

useMemo is a React hook that lets you cache the result of a calculation that is value of a calculation between re-renders

If you are calculation something that is resource intensive, then you can cache the result of the calculation

And as long as the input of the calculations do not change you don't have to do the calculation again

Contrast this with

useCallback

useCallback is a react hook that lets you cache a function definition between re-renders.

unlike useMemo, useCallback does not call the function that you provided. Instead it caches the function itself

you can think of useCallback as a wrapper around useMemo with the additional benefits

This article is brought to you by DeadSimpleChat Chat API and SDK for your website and apps

Now, what does that mean?  and How is that useful?

Let us consider an example to better understand this

Exploring the Differences

You can think of a website sellings products online. With one product on a single page and a buy button on the submit form

We have a Form component from which users can order products, and we have wrapped it in a memo

Now, you want to pass a function to it as a prop

let us look at the code

export default function ProductPage({ productId, referrer }) {
  //function to memorize or cache
    function handleSubmit(orderDetails) {
    post('/product/' + productId + '/buy', {
      referrer,
      orderDetails
    });
  }

  return <Form onSubmit={handleSubmit} />;
}
product page

The problem here is that, every re-render would create a new instance of the function.

Just as {} creates a different Object, the function declarations like function () {} or () =>{} creates a new instance of the function

Now,  the handleSubmit function is declared inside the ProductPage component.

So, everytime ProductPage renders a new instance of handleSubmit will be created

By itself creation of a new function is not a problem but the whole point of memorizing or caching the function is skipping the re-rendering of the component when no props have changed

However, if a function is passed as a prop to a memorized component is always different due to being re-declared on every re-render. It defeats the purpose of memorization

In this case the memorized function would re-render every time, since is function instance is different every time

To memorize a function with useMemo, you will have to return another function like so

export default function Page({ productId, referrer }) {
  //Memorizing the function
    const handleSubmit = useMemo(() => {
//returning another function
        return (orderDetails) => {
      post('/product/' + productId + '/buy', {
        referrer,
        orderDetails
      });
    };
  }, [productId, referrer]);

  return <Form onSubmit={handleSubmit} />;
}

Here useCallback comes to our help. you can wrap the function in useCallback instead of useMemo to avoid having to write an extra nested function

export default function Page({ productId, referrer }) {
  const handleSubmit = useCallback((orderDetails) => {
    post('/product/' + productId + '/buy', {
      referrer,
      orderDetails
    });
  }, [productId, referrer]);

  return <Form onSubmit={handleSubmit} />;
}

The above two examples are the same. The only benefit of useCallback is that it lets you avoid that nest function

Understanding Memorization

Before understanding useMemo and useCallback it is essential to understand the concept of memorization

Memorization means caching the result of an expensive calculation, so that we do not run the calculation again unless the inputs have changed

This techniques are used to significantly improve performance where expensive computations are performed

How useMemo is used

the useMemo hooks is referenced as

useMemo(valueCalculation, dependencies);

valueCalculation is a function that returns a value that is to be memorized or cached and dependencies is an array of values from the components contexts.

If any value in the dependencies array changes then the valueCalculation function is re-invoked

Examples and Use-Cases of useMemo

Caching and skipping expensive calculation

One of the major advantages of useMemo is caching of expensive calculations to avoid calculating them on every re-render

And only run the expensive calculation when a input or prop changes, thus optimizing performance

const expensive = useMemo(() => {
    return timeConsumingCalculation(hugeDataset);
}, [hugeDataset]);
usememo

Here the timeConsumingCalculation will only happen if the hugeDataset changes

Skipping Re-rendering of Components

Child components can re-render if something in the parent (state changes) changes, if props are being passed down to the child

const someInformation = useMemo(() => {
    return timeConsumingCalculation(data);
}, [data]);

<ChildComponent data={someInformation} />

Memorizing dependency of another hook

Many times a hook may have a dependency that has been derived from a state or a prop

You can memorize this dependency instead of recalculating the dependency on every render

const coolData = useMemo(() => processData(data), [data]);
useEffect(() => {
    fetchData(coolData);
}, [coolData]);

Memorizing a function

You can memorize a function with useMemo but you don't need to do that cause the useCallback hook is available for that

const handleClick = useMemo(() => {
    return () => {
        console.log("This button has been clicked!");
    };
}, []);
Memorixing a function

Troubleshooting with useMemo

the calculation is running 2 with every re render

This happens during development mode for certain side-effects.

useMemo should return an Object but is returning undefined

ensure that your function is returning the correct value

Calculation rerun even if encapsulated in useMemo

The dependencies are changing at every re-render. ensure that the props  or dependencies are not changing or you might need to use useCallback instead

Need to call useMemo for each item in a loop but it's not allowed

You might need to restructure you component, each item can be a component with its own useMemo

Examples and use-cases of useCallback

here is the reference

useCallback(fn, dependencies)
usecallback

Skipping re-rendering of components

If a component is wrapped in a useMemo then passing a callback function to it will cause it to re render as function declaration create new functions

You can prevent the component to rerender because of the callbackfunction by using useCallback instead of useMemo

const handleSubmit = useCallback((someFunction) => {
 
}, []);

Updating state from a memorized callback

When you are dealing with updates in the memorized callback, it may lead to unexpected behaviour if the callback references to the state which is not updated

Preventing the effect from firing too often

In combination with useEffect the  useCallback can prevent the effect from firing too often. If the dependencies have not changed

Optimizing a custom hook

Inside custom hooks the useCallback can be used to memorize dependencies to improve performance

You might be interested in some of our other articles

conclusion

In this article we learnt about useMemo and useCallback. What are the differences between them and how do they work

Basically, useCallback is a wrapper around useMemo with additional benefit of caching hte function itself rather than the value returned by the function

This helps when you are passing a callback function as a prop to the component and you want to memorize it

This is because the funtion declaration such as function() {} or ()=>{} creates a new function and if oyu wrapped this component in useMemo instead of useCallback your component woild re render every time regardless of other props changing or not because new function is being created every time

To avoid this cache the function declaration itself instead of the returned value by using useCallback

I hope you liked the article. Thank you for reading