useCallback hook

useCallback Hook in React

In React, performance optimization is a crucial aspect of building user interfaces. One of the most common performance bottlenecks is re-rendering components, which can slow down the app. To mitigate this, React provides the useCallback hook, which allows you to optimize component re-renders by caching a function and its dependencies [1].

This post is a continuation of my series with React hooks, so if you are not familiar with this topic, please start from this post [2].

How to use useCallback hook?

The useCallback hook is a powerful tool in the React developer’s toolkit that allows you to optimize the performance of your components. It allows you to cache a function and its dependencies, ensuring that it only changes when one of its dependencies changes. This way, you can reduce the number of unnecessary re-renders and improve performance.

A useCallback hook is used by passing two arguments: a function and an array of dependencies. The hook returns a memoized version of the function that only changes when one of its dependencies changes.

Here’s a basic example of how to use the useCallback hook:

import React, { useCallback } from 'react';

const MyComponent = ({ data }) => {
  // useCallback wraps your function to memoize it - whenever "data" changes, useCallback will return new version of our callback function
  const handleClick = useCallback(() => {
    console.log(data);
  }, [data]);

  return <button onClick={handleClick}>Click me</button>;
};

In this example, the handleClick function is only re-created when the data prop changes. This way, you can be sure that the component only re-renders when it’s necessary.

It’s important to note that the dependencies array should include all values from your component that are used within the function. If you try to use a variable that is not in a dependency array in your callback, there is a high chance that the function will be called with an outdated value.

If you will pass an empty array as a second argument, then your function will be created only once on the first component render, and for the rest of the component live it won’t be recreated.

When should you a useCallback hook?

Typically you would want to use useCallback hook in following scenarios:

#1 When handling events

If you have an event handler that accesses props or state, using useCallback can ensure that the event handler only changes when the relevant props or state changes.

import React, { useCallback } from 'react';

const MyComponent = ({ data }) => {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  return (
    <div>
      <p>{data}</p>
      <button onClick={handleClick}>Click me</button>
      <p>Count: {count}</p>
    </div>
  );
};

#2 When passing a callback to a child component

If you pass a callback from a parent component to a child component, and the parent component re-renders frequently, it can cause the child component to re-render as well, even if its props haven’t changed. Using useCallback can avoid this.

import React, { useCallback } from 'react';

const ParentComponent = ({ onClick }) => {
  const handleClick = useCallback(() => {
    console.log('Parent component');
  }, []);

  return <ChildComponent onClick={handleClick} />;
};

const ChildComponent = ({ onClick }) => {
  return <button onClick={onClick}>Click me</button>;
};

In this example, the handleClick function is only created once, even if the parent component re-renders. This way, you can be sure that the child component will not re-render unnecessarily.

#3 API call functions

If you make an API call inside a component, you can use useCallback to ensure that the API call is only made when the relevant props or state change. You can use this function later in useEffect or useMemo, or call it directly after some DOM event [3][4]:

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

const MyComponent = ({ data }) => {
  const [dataFromAPI, setDataFromAPI] = useState(null);

  const fetchData = useCallback(async () => {
    const response = await axios.get('https://api.example.com/data');
    setDataFromAPI(response.data);
  }, []);

  return (
    <div>
      <p>{data}</p>
      <button onClick={fetchData}>Fetch data</button>
      <p>Data from API: {dataFromAPI}</p>
    </div>
  );
};

In this example, the fetchData function is only created once, even if the component re-renders. This way, you can be sure that the API call will only be made when it’s necessary.

Basically, you can use this hook to wrap up every function in your functional component. You should avoid it only if you are sure it is unnecessary to memoize your function because your component rarely re-renders.

Conclussion

In conclusion, the useCallback hook is a useful tool for optimizing the performance of your React components. It allows you to memoize expensive function definitions and prevent unnecessary re-renders, improving the overall performance of your application.

List of references

Leave a Comment

Your email address will not be published. Required fields are marked *