What is the #1 rule before optimizing React performance?
Measure first. Use the React DevTools Profiler to identify actual bottlenecks. Premature optimization adds complexity without guaranteed benefit.
What does React.memo do?
Wraps a component so it skips re-rendering when its props haven’t changed (shallow comparison). It’s a performance hint, not a guarantee — React may still re-render it.
When should you use React.memo?
When a component re-renders often with the same props, and its render is expensive. Don’t use it on every component — the shallow comparison itself has a cost.
Why is React.memo useless if you pass a new object or function as a prop on every render?
Shallow comparison checks reference equality (===). A new object or function literal is a different reference every render, so memo always sees ‘changed’ props and re-renders anyway.
What does useMemo do?
Caches the result of a computation between renders. It only recomputes when one of its dependencies changes. Syntax: const value = useMemo(() => expensiveCalc(a, b), [a, b]).
When should you use useMemo?
When a calculation is noticeably slow (1ms+), its dependencies rarely change, or the result is passed as a prop to a memoized child and needs a stable reference.
What does useCallback do?
Caches a function definition between renders. It returns the same function reference unless its dependencies change. Syntax: const fn = useCallback(() => { … }, [deps]).
When should you use useCallback?
Primarily when passing a callback as a prop to a child wrapped in React.memo. Without useCallback, the function is recreated each render, defeating memo’s shallow comparison.
How do React.memo, useMemo, and useCallback work together?
A typical chain: useCallback stabilizes a function reference → useMemo stabilizes a computed value → React.memo on the child skips re-render because both props are referentially equal.
What happens if you wrap everything in useMemo/useCallback unnecessarily?
You add overhead (dependency array comparisons, increased memory for cached values, harder-to-read code) without measurable performance gain. It can actually make things slower.
What is the most common source of performance problems in React apps?
Chains of useEffect calls that update state, causing cascading re-renders. Removing unnecessary Effects is often more impactful than adding memoization.
What is code splitting and React.lazy?
Code splitting breaks your bundle into smaller chunks loaded on demand. React.lazy(() => import(‘./HeavyComponent’)) loads a component only when it’s first rendered, reducing initial load time.
What is virtualization (windowing) and when should you use it?
Rendering only the visible items in a long list (plus a small buffer), not all 10,000 rows. Libraries like react-window and react-virtuoso implement this. Use it for lists with 100+ items.
What is debouncing in the context of React performance?
Delaying a state update until the user stops a rapid action (like typing). Instead of re-rendering on every keystroke, you wait for a pause — reducing total renders.
What does the React DevTools Profiler show you?
Each commit (DOM update), which components rendered, render duration, what triggered each render (state, parent, context), and a flame graph of the component tree.
Should you optimize in development mode or production mode?
Always measure in production mode. Development mode adds extra checks (like double-rendering in StrictMode) that make timings inaccurate.
What is the React Compiler (React 19+) and how does it affect memoization?
It automatically analyzes components and inserts memoization where beneficial — potentially eliminating the need for manual useMemo/useCallback in most cases.
What is a ‘pure component’ and why does it matter for performance?
A component that returns the same output for the same props/state. Pure components are safe to memoize and safe for React to skip re-rendering when inputs haven’t changed.
How can moving state down (closer to where it’s used) improve performance?
If state is high in the tree, updating it re-renders the entire subtree. Moving it into a lower component limits re-renders to just that component and its children.
What is composition as a performance pattern?
Passing children as JSX (props.children) instead of rendering them directly. The parent can re-render without re-rendering the children, because the children’s JSX was created by the grandparent.