█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Programming Languages/React (Standalone Deep Dive)/Performance Optimization
50 minAdvanced

Performance Optimization

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.

Prerequisites:State Management

Measure before optimizing

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.

React.memo + useCallback

Memoize components + stable function references.

tsx
// React.memo: skip re-render if props are shallow-equal
const Row = React.memo(function Row({ user, onSelect }) {
return <button onClick={() => onSelect(user.id)}>{user.name}</button>;
});
// In parent: useCallback to keep onSelect stable
function 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.

Code splitting with lazy + Suspense

Don't ship every route's JS up front.

python
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).

Virtualization for big lists

Render only visible items.

html
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.

Common mistakes only experienced React devs avoid

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.

Quick Check

When is React.memo a perf win?

Pick the senior answer.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←State Management: Local vs Global
Back to React (Standalone Deep Dive)
React Patterns→