When to use UseCallback

We all know that with the advent of React 16.8, hooks came into our lives. Indeed, they simplify the coding process by using functional components versus classes. But some hooks raise a lot of questions from the developer. In this article, we will look at examples when you need to use UseCallback, and when you can do without it.

We know from documentation that UseCallback returns a memoized version of the callback, in simple words, returns the same reference to the function until one of the dependencies changes.

const memoizedCallback = useCallback(
 () => {
    doSomething(a, b);
  },
  [a, b],
);

Let’s take an example.

We have a page with an input, a list of displaying elements and a button that adds the entered element to the list. When you click on the list item itself, it will be deleted. We will take the default list of 5 cities that we will edit.

const listOfCities = ['Beijing','Tokyo','Kinshasa','Moscow','Jakarta'];

const Page = () => {
  const [name, setName] = useState('');
	const [list, setList] = useState(listOfCities);
  
  const handleClick = () => {
      setList([...list, name]);
      setName('');
  };

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setName(event.target.value);
  };
  
  const handleRemoveClick = (item: string) => {
    const filteredList = list.filter((listItem) => listItem !== item);

    setList(filteredList);
  };
  
  console.log('Page render');
  
  return (
    <div>
      <input type="text" value={name} onChange={handleChange}/>
      <button onClick={handleClick}>Add</button>
			<CitiesList list={list} onRemoveClick={handleRemoveClick}/>
    </div>
  );
};

And list display components

export const CitiesList = ({list, onRemoveClick}) => {
  console.log('List render');
  
  return list.map((item) => {
    return <City key={item} city={item} onRemoveClick={onRemoveClick} />;
  });
};


export const City = ({city, onRemoveClick}) => {
  const handleCityClick = () => onRemoveClick(сity);

  console.log('City render');

  return <div onClick={handleCityClick}>{city}</div>
});

So, what are the problems with performance now? Let’s run it and see what we get.

Let’s open the console and see

Everything seems to be logical, the page, the list component and its 5 elements have been rendered.

We begin to enter symbols into the input and see that for each entered symbol, a similar rendering takes place in all components. The problem is clear, changes in the value of the input (state name), causes all child components to render.

We have three callback functions that could theoretically be wrapped in UseCallback. Let’s analyze them separately.

By wrapping handleClick, handleChange, or handleCityClick v UseCallbackalas, this will not improve the performance in any way. UseCallback this is also a function that, on each render, will re-compare the dependencies and return a new or old reference to the function.

By wrapping handleRemoveClick v UseCallback, will reduce the number of renders provided we wrap the SitiesList in React.memo, more about it can be found in documentation

const handleRemoveClick = useCallback((item: string) => {
    const filteredList = list.filter((listItem) => listItem !== item);

    setList(filteredList);
}, [list]);
const CitiesList = React.memo(({ list, onRemoveClick }) => {
  console.log("List render");

  return list.map((item) => {
    return <City key={item} item={item} onRemoveClick={onRemoveClick} />;
  });
});

Now, when you enter characters in the input, the СitiesList component is not re-rendered. On a list of 5 elements, the improvement in performance will not be so great, but it clearly shows how it can be improved if necessary.

In this example, it was possible to move the input with the button and its state into a separate component, then the need to use UseCallback would no longer be relevant, so don’t make performance optimizations until you really need to.

What conclusions can be drawn from this?

UseCallback is a useful and useful thing to help improve your performance. But its application is not always relevant. Use UseCallback for functions that are passed to memory-intensive components for display. Do performance optimizations after writing and refactoring your code.

Hope you found this article helpful. Bye everyone 🙂

Similar Posts

Leave a Reply

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