The problem with unnecessary re-renders
React's virtual DOM is efficient, but that's not a license to be careless about re-renders. Every one costs CPU cycles, and in a complex app those cycles add up into something a user actually feels.
When a component re-renders, React runs the component function, diffs the new virtual DOM against the old one, and updates the real DOM if anything changed. None of that is free.
Understanding useMemo
useMemo is the first line of defense against an expensive calculation running on every render. It memoizes a computed value and only recalculates when its dependencies change.javascriptconst expensiveValue = useMemo(() => {return computeExpensiveValue(a, b)}, [a, b])
useCallback
useCallback does the same thing for functions: it returns a memoized callback that only changes when its dependencies do.javascriptconst handleClick = useCallback(() => {doSomething(a, b)}, [a, b])
React Compiler
React Compiler (formerly React Forget) automates a lot of this memoization work, which should cut down on how much manual optimization is necessary. Worth watching, not yet a reason to stop reasoning about renders yourself.
What I actually do
Profile before optimizing. Most re-render problems aren't where you'd guess. Use React DevTools to find the actual source instead of memoizing defensively. Apply
useMemo and useCallback where the profiler says to, not everywhere. And keep an eye on where React Compiler lands, since it'll change how much of this is worth doing by hand.