Pointless useCallback

Incorrect usage

useCallback in the code snippet below is pointless:

const Counter = () => {
  const [count, setCount] = useState(0);

  // `useCallback` is pointless
  const handleIncrement = useCallback(() => {
    setCount((prev) => prev + 1);
  }, []);

  return <button onClick={handleIncrement}>{count}</button>;
};

By "pointless" I mean that it doesn't really do anything - it doesn't make the code run a little bit faster. On the contrary - it makes it a little bit slower, compared to not using useCallback at all.

Why is it not faster?

  • useCallback is used to keep the same reference to a function, to minimize the number of re-renders of a React componet. But it doesn't apply to the native elements like buttons Why is it not slower?
  • useCallback reconstructs the function on each re-render. So you re-cache the function on each rerender. Caching is used to make things go faster. But if you're not using cache, it means that you're just allocating memory you're not gonna access.

Correct usage

const Counter = () => {
  const [count, setCount] = useState(0);

  const handleIncrement = () => setCount((prev) => prev + 1);

  return <button onClick={handleIncrement}>{count}</button>;
};

When to actually use useCallback?

Another incorrect usage

You might want to consider using useCallback if you're passing the function to a React component:

const AppButton = ({ label, onClick }) => (
  <button onClick={onClick} className="btn">
    {label}
  </button>
);

const Counter = () => {
  const [count, setCount] = useState(0);

  const handleIncrement = useCallback(() => {
    setCount((prev) => prev + 1);
  }, []);

  // the AppButton still re-render, even if you memoize the function with `useCallback`
  return <AppButton onClick={handleIncrement} label={count} />;
};

But contrary to popular belief, that is not enought.

Correct usage

You have to combine memo with useEffect to make it work:

// use `memo` to memoize the component
const AppButton = memo(({ label, onClick }) => (
  <button onClick={onClick} className="btn">
    {label}
  </button>
));

const Counter = () => {
  const [count, setCount] = useState(0);

  const handleIncrement = useCallback(() => {
    setCount((prev) => prev + 1);
  }, []);

  return <AppButton onClick={handleIncrement} label={count} />;
};

Further reading

results matching ""

    No results matching ""