Developer Cheatsheets
react-performance-debugging
Usememo Vs Usecallback

Cheatsheet: Understanding useMemo and useCallback in React

React provides us with a variety of hooks, each with its own set of use cases and considerations. Today, we'll focus on useMemo and useCallback, unraveling their differences and understanding when to reach for each.

useMemo:

useMemo returns a memoized value. You can think of this hook as a way to tell React to store a value and only recompute it when certain dependencies change. This is extremely useful for expensive calculations.

Here's an example where we compute factorial of a number using useMemo:

FactorialComponent.tsx

import React, { useState, useMemo } from 'react';
 
const calculateFactorial = (num: number): number => {
  if (num === 0) return 1;
  let i = num;
  while (--num) i *= num;
  return i;
};
 
const FactorialComponent: React.FC = () => {
  const [number, setNumber] = useState(5);
 
  const factorial = useMemo(() => calculateFactorial(number), [number]);
 
  return (
    <div>
      <input
        type="number"
        value={number}
        onChange={(e) => setNumber(Number(e.target.value))}
      />
      <p>Factorial: {factorial}</p>
    </div>
  );
};
 
export default FactorialComponent;

In the above example, the factorial calculation will only run when the number state changes.

useCallback:

useCallback on the other hand, returns a memoized version of the callback function that only changes if one of the dependencies has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.

Here's an example where we use useCallback to ensure that the handleClick function we pass to a child component doesn't change unless necessary:

CallbackComponent.tsx

import React, { useState, useCallback } from 'react';
import ChildComponent from './ChildComponent';
 
const CallbackComponent: React.FC = () => {
  const [counter, setCounter] = useState(0);
 
  const handleClick = useCallback(() => {
    setCounter((counter) => counter + 1);
  }, []);
 
  return (
    <div>
      <ChildComponent onClick={handleClick} />
      <p>Counter: {counter}</p>
    </div>
  );
};
 
export default CallbackComponent;

ChildComponent.tsx

import React, { ReactElement } from 'react';
 
interface ChildProps {
  onClick: () => void;
}
 
const ChildComponent: React.FC<ChildProps> = React.memo(({ onClick }) => {
  console.log('ChildComponent rendered');
  return <button onClick={onClick}>Increase Counter</button>;
});
 
export default ChildComponent;

In this case, the child component will not rerender unnecessarily because the handleClick callback maintains its identity across rerenders, thanks to useCallback.

When to Use useMemo and useCallback

As a rule of thumb, use useMemo when you need to optimize expensive computations and useCallback when you pass callbacks to optimized child components.

However, it's important to note that over-optimization can lead to more harm than good. Both useMemo and useCallback come with their own overhead, so use them judiciously and only when necessary.

So there you have it, a concise exploration into the realm of useMemo and useCallback. These tools can be a boon to your React performance, but remember the golden rule of optimization: don't do it prematurely. Happy coding!