React re-renders components when state or props change. Unnecessary re-renders hurt performance. React.memo() wraps components to skip re-rendering when props haven't changed.
useMemo caches computed values: const expensive = useMemo(() => heavyCalc(data), [data]). useCallback caches functions: const handler = useCallback(() => doSomething(id), [id]).
React DevTools Profiler identifies which components re-render and why. Batch state updates to reduce renders. Avoid creating objects/functions in JSX props.
Code splitting with React.lazy() and Suspense loads components on demand. Virtual scrolling (react-window) handles large lists. Concurrent features (startTransition, useDeferredValue) keep the UI responsive.
Key optimization: move state down, lift content up. Smaller components re-render faster. Profile before optimizing — measure, don't guess.