How to Use useCallback Hook in React?
How to Use useCallback Hook in React?

Hello and welcome back to the channel. In this video you will learn one of the important React hooks and it's useCallback. It's really nice for performance optimisations so let's jump right into it.

Here I have empty create-react-app project where we can directly start writing code. If you don't know how to generate react project with create-react-app I made a video on that so go check it out first.

I you can see in browser I have just a single h1 tag and it's our App.js component. Let's have a look. So it's a normal stateless React component with markup inside.

As we are using React bigger than 16 version (actually 17) we can use hooks inside without installing any additional packages.

It is crucial to understand useMemo hook first before you jump in useCallback hook so if you didn't see my video about useMemo pause this video and go check that one first. I will leave a link in the description box below.

And as always let's check on the example. Let's say that we have a search field inside App and also a child component that renders a list of users.

const initialUsers = [
  { id: "1", name: "Foo" },
  { id: "2", name: "Bar" },
];

const List = React.memo(({ users }) => {
  console.log("List rerendered", users);
  return (
    <ul>
      {users.map((user) => (
        <div key={user.id}>
          {user.name}
        </div>
      ))}
    </ul>
  );
});

function App() {
  console.log("render");
  const [text, setText] = useState("");
  const [users, setUsers] = useState(initialUsers);

  const handleText = (event) => {
    setText(event.target.value);
  };

  return (
    <div>
      <h1>React hooks for beginners</h1>
      <input type="text" value={text} onChange={handleText} />
      <List users={users} onRemove={handleRemove} />
    </div>
  );
}

Now we can wrap our List component in React.useMemo function. If you don't know what React.useMemo is doing it remembers the previous render of the component and if state or props don't change it won't render it again. Also it helps to show the benefits of using useCallback for us later. But be aware that useMemo hook and React.useMemo are 2 different things.

const List = React.memo(({ users }) => {}

Now let's add a remove function so we can remove users from the list.

const List = React.memo(({ users, onRemove }) => {
  console.log("List rerendered", users);
  return (
    <ul>
      {users.map((user) => (
        <div key={user.id}>
          {user.name} <span onClick={() => onRemove(user.id)}>X</span>
        </div>
      ))}
    </ul>
  );
});

and update a call

const handleRemove = (userId) => {
  console.log("handleRemove");
  const filteredUsers = users.filter((user) => user.id !== userId);
  setUsers(filteredUsers);
},


<List users={users} onRemove={handleRemove} />

So we are just filtering users inside App component. As you can see in browser everything is working as expected.

But here is the 1 thing. As you can see when we are typing in the input our List component is being rerendered. As you can see typing means that we change text property which causes the rerendering of App component. But as we wrote React.memo actually our List component should not be rerendered because it's props were not changed.

But here is a thing. Inside hooks all functions that we are defining are redefined again every rerender. Which means that our handleRemove function is actually a new function every time when rerender of App component happens. This is why our List component is rerendered. Because actually it's props change. But not the users list. It's onRemove function which is every time a new function. And this is actually a problem for us because we don't want to rerender our List if nothing was changed.

This is exactly the usecase for useCallback. Let's wrap our handleRemove function in useCallback hook.

const handleRemove = useCallback(
  (userId) => {
    console.log("handleRemove");
    const filteredUsers = users.filter((user) => user.id !== userId);
    setUsers(filteredUsers);
  },
  [users]
);

And here we are defining the dependencies. useCallback memoizes the function. Which means React will use the same function again and again until users property will be changed.

As you can see in browser now we don't get rerenders of the child component. This is exactly what we wanted to achieve.

So here are the most important differences between useMemo and useCallback. useMemo memoizes the calculated function so if we assign useMemo to the variable we will write the result of the function there. When we are using useCallback we are memoizing a function. So function is available for use for future use as any normal function.

So this is how you can use useCallback hook. But I always recommend to minimise it's usage and not to do optimisations until you have problems.

If "React hooks for beginners" is too easy for you I have a full hooks course which is going 8 hours where we are creating real application from scratch. I will link it down in the description below.

📚 Source code of what we've done