After this lesson, you will be able to: Apply React.memo, useMemo, useCallback, code splitting with lazy/Suspense, virtualization with react-virtual.
Most apps don't need perf tuning. When they do, these are the tools.
React DevTools Profiler records renders + flames. Find the slow component; check why it re-renders. Most perf wins come from preventing unnecessary renders, not making renders faster.
Memoize components + stable function references.
// React.memo: skip re-render if props are shallow-equalconst Row = React.memo(function Row({ user, onSelect }) {return <button onClick={() => onSelect(user.id)}>{user.name}</button>;});// In parent: useCallback to keep onSelect stablefunction List({ users }) {const [selected, setSelected] = useState(null);const handleSelect = useCallback((id) => setSelected(id), []);return users.map((u) => <Row key={u.id} user={u} onSelect={handleSelect} />);}// Without useCallback, handleSelect is a NEW function each render, Row re-renders anyway.
Don't ship every route's JS up front.
import { lazy, Suspense } from "react";const Settings = lazy(() => import("./Settings"));function App() {return (<Suspense fallback={<Spinner />}><Settings /></Suspense>);}// Webpack/Vite splits Settings into a separate chunk; loaded on demand.// Combine with route-level splitting (React Router does this automatically).
Render only visible items.
import { useVirtualizer } from "@tanstack/react-virtual";function BigList({ items }) {const parentRef = useRef(null);const v = useVirtualizer({count: items.length,getScrollElement: () => parentRef.current,estimateSize: () => 40,});return (<div ref={parentRef} style={{ height: 400, overflow: "auto" }}><div style={{ height: v.getTotalSize(), position: "relative" }}>{v.getVirtualItems().map((vi) => (<div key={vi.key} style={{ position: "absolute", top: vi.start, height: vi.size }}>{items[vi.index].name}</div>))}</div></div>);}// 100K rows; only ~20 rendered at a time. Smooth scrolling.
Wrapping every component in React.memo. Premature; adds overhead. useMemo/useCallback on primitives. Pointless. Code splitting on tiny chunks. Network round-trips cost more than the saved bytes. Skipping the Profiler. Optimizing without measuring is guessing.
Pick the senior answer.
Sign in and purchase access to unlock this lesson.