When to use the two hooks - useCallback and useMemo?

Every state change in React can cause re-rendering which can affect badly on application. Mostly when the component size gets increased. useCallback and useMemo hooks are used for improvising the performance of React application.

Does useCallback and useMemo do the same thing?

Though both are used for performance optimization, it might be confusing for developers regarding their use-case. So let’s understand them thoroughly.

Before diving deeply into their difference, let’s understand why they are used.

  • As mentioned above, both hooks are used for performance optimization.
  • If our application is doing frequent re-rendering then based on the use-case we can use one of them.

Let’s see how syntactically different they are:-

useCallback(()=>{
  doSomething();
}, [dependencies]);

useMemo(()=>{
  doSomething();
}, [dependencies]);

As we can see, there is no such difference in their syntax except in their naming. Both hooks accept a function and a dependency array.

How is useMemo different from useCallback?

The main difference between useMemo and useCallback hook is, useMemo returns memoized value and useCallback returns memoised function.

Still confused? No problem. We will understand the difference by considering one example.

Let’s say we have one parent component,

import { React, useState } from 'react';
import ChildComponent from './ChildComponent'

function App() {
  const [num, setNum] = useState(0);

  return(
    <div>
      <h1>{num}</h1>
      <ChildComponent />
      <button onClick={() => setNum(num + 1)}> Addition </button>
    </div>
  );
}

and a child component

import { React } from 'react';

function ChildComponent() {
  console.log("child component rendered")
  
  return(
    <div>
      <h1>Hello World</h1>
    </div>
  );
}

export default ChildComponent;

We can observe that the console statement - child component rendered is getting printed every time we click on the Addition button.

Though the state change is accuring in parent component only, the child component is re-rendering unnecessarily.

Let’s have a look on how we can avoid that.

Understanding useMemo

In this situation useMemo can give us memoized result. Just call the child component by wrapping in useMemo.

So, the parent component will look like:

import { React, useState, useMemo } from 'react';
import ChildComponent from './ChildComponent'

function App() {
  const [num, setNum] = useState(0);

  const getChildComp = useMemo(() => <ChildComponent />, []);

  return(
    <div>
      <h1>{num}</h1>
      {getChildComp}
      <button onClick={() => setNum(num + 1)}> Addition </button>
    </div>
  );
}

We can observe here that, the console statement is not getting printed as we click on Addition button

Thus useMemo helped us in increasing performance in this situation.

Now, let’s see how useCallback works.

Understanding useCallback

Just create a function in the parent component and pass it to the child component. So that the parent component will look like,

import { React, useState } from 'react';
import ChildComponent from './ChildComponent'

function App() {
  const [num, setNum] = useState(0);

  const handleUpdateNum = () => {
    //some code
  };

  const getChildComp = useMemo(
    () => <ChildComponent handleUpdateNum={handleUpdateNum} />,
    [handleUpdateNum]
  );

  return(
    <div>
      <h1>{num}</h1>
      {getChildComp}
      <button onClick={() => setNum(num + 1)}> Addition </button>
    </div>
  );
}

Now, if we try to click on the Addition button, we can see child component rendered on a console. So, useMemo won’t help out in this situation.

Because every time the parent component gets re-rendered, handleUpdateNum function got re-created.

There useCallback comes into the picture which returns us memoized function.

Let’s wrap the handleUpdateNum function by useCallback hook and see the result. So the code in parent component will look like this,

import { React, useState, useCallback } from 'react';
import ChildComponent from './ChildComponent'

function App() {
  const [num, setNum] = useState(0);

  const handleUpdateNum = useCallback(() => {
    //some code
  }, []);

  const getChildComp = useMemo(
    () => <ChildComponent handleUpdateNum={handleUpdateNum} />,
    [handleUpdateNum]
  );
  
  return(
    <div>
      <h1>{num}</h1>
      {getChildComp}
      <button onClick={() => setNum(num + 1)}> Addition </button>
    </div>
  );
}

Now we can see, even after the change in the parent component’s state, the child component is not re-rendering.

Conclusion

Though we have explored useCallback and useMemo, we can make use of these hooks as per our requirement. Just consider these hooks as fine-tuning in React. It can’t fix badly written code but if everything is up to the mark, these hooks will provide their extra benefits. For reference, please use this link.

Need help on your Ruby on Rails or React project?

Join Our Newsletter