Kept seeing the same advice everywhere: wrap things in useMemo, useCallback everything, React.memo all the things.
Then i profiled an app I'd "optimized" this way, the memoization overhead was costing more than the renders it was preventing
with the react compiler now auto-memoizing at build time, most manual useMemo/useCallback is becoming dead weight.
wrote up what actually fixes react performance in practice:
-
state colocation: move state closer to where it's used. this one change beats every useMemo in your codebase. seriously.
-
the children pattern: pass children from above so they don't re-render when parent state changes. zero memoization needed.
-
useTransition: mark non-urgent updates as transitions. input stays responsive, heavy renders happen in background.
-
useDeferredValue: same idea but for values from props you don't control. smarter than debouncing.
-
code splitting: lazy() + Suspense for routes and heavy components. don't lazy-load a button though.
-
profile before optimizing: react devtools profiler, chrome performance tab, core web vitals. if you haven't measured it, don't optimize it.
also covered 5 performance bugs i keep finding in production codebases:
-
components defined inside other components (full remount every render, not re-render)
-
useEffect chains causing cascade re-renders
-
context providers sitting too high in the tree
-
unstable keys (Math.random() as key is surprisingly common)
-
object/array literals in JSX props breaking React.memo
the useEffect chain one is probably the most common. three effects that depend on each other = three render cycles for one user action.
what's the worst react perf bug you've had to track down?