Advanced React, explained with pictures

Eight topics every React developer meets sooner or later. Each one has a short answer, a looping animated diagram, and a small code example, so you can learn it all on this one page.

Animated component tree: a state change re-renders a parent and its children, while memoized children skip the update App (state changes) Re-renders memo: skipped Re-renders Goal: only re-render what actually changed
The cyan dot is a state update travelling down the tree. Green means React skipped the work.
Topic 1

React Performance Optimization Techniques Every Developer Should Know

React is slow only when it re-renders too much or ships too much code. Find the slow part with the Profiler, then fix it with memoization, smaller state, lazy loading and list virtualization.

Flowchart for fixing a slow React app: measure, find cause, apply the right fix, measure again 1. Measure 2. Find cause Too many rendersmemo, state down Heavy bundlelazy, split Long listsvirtualize
Never guess. Measure, fix one thing, measure again.
const Row = React.memo(function Row({ item }) {
  return <li>{item.name}</li>;   // skips if item is unchanged
});

Quick wins

  • Keep state as low in the tree as possible.
  • Give list items a stable key, never the array index when order can change.
  • Do not create new objects in props on every render.

Official docs: React.memo · React DevTools

useMemo vs useCallback →

Topic 2

useMemo vs useCallback: Understanding When to Use Them

useMemo remembers a calculated value. useCallback remembers a function. Both only recompute when something in their dependency array changes.

useMemo caches a value and useCallback caches a function between two renders useMemouseCallback Render 1 Render 2 cached valuesame deps = reuse Render 1 Render 2 same functionsame reference
Both skip work on Render 2 when dependencies did not change.
useMemo useCallback
Returns A value A function
Use for Slow calculations, stable objects Handlers passed to memoized children
const total = useMemo(() => items.reduce((s, i) => s + i.price, 0), [items]);
const onSave = useCallback(() => save(id), [id]);

Rule of thumb: do not add them everywhere. Use them when a calculation is truly slow, or when a function goes to a React.memo child.

Docs: useMemo · useCallback

← PerformanceContext vs Redux →

Topic 3

React Context API vs Redux Toolkit: Which One Should You Choose?

Choose Context for small, slow-changing shared values like theme or logged-in user. Choose Redux Toolkit when many parts of a large app update shared state often and you want strong debugging tools.

Context passes a value from a Provider straight to a deep child; Redux dispatches actions to a store that updates subscribed components Context APIRedux Toolkit Provider Middle (ignores it) useContext dispatch Store Component A Component B
Context skips the middle components. Redux sends every change through one store.
Question Context Redux Toolkit
Setup Built in, very small Install a package
Update often? Can re-render all consumers Components subscribe to slices
Debugging Basic Redux DevTools time travel
const todos = createSlice({
  name: "todos", initialState: [],
  reducers: { add: (state, a) => { state.push(a.payload); } }
});

Docs: Context · Redux Toolkit

← useMemo vs useCallbackCustom Hooks →

Topic 4

Custom Hooks in React: Write Reusable Logic Like a Pro

A custom Hook is a function whose name starts with use and that calls other Hooks. It lets many components share the same logic without copying code.

Two components share one custom Hook, useFetch, which calls an API and returns data UserList ProductList useFetch(url) API
One Hook, written once, used by many components.
function useFetch(url) {
  const [data, setData] = useState(null);
  useEffect(() => {
    fetch(url).then(r => r.json()).then(setData);
  }, [url]);
  return data;
}
const users = useFetch("/api/users");
  • Each component gets its own separate state, only the logic is shared.
  • Follow the Rules of Hooks: call them at the top level only.

Docs: Reusing logic with custom Hooks

← Context vs ReduxServer Components →

Topic 5

React Server Components: The Future of React Development

Server Components run only on the server and send finished output to the browser. Users download less JavaScript, and your components can read databases directly.

A Server Component reads the database on the server and streams output to the browser, where only a small Client Component needs JavaScript Server Componentreads database Ready outputno component JS Browser shows pagefast first paint Client: Like button
Only interactive pieces ship JavaScript to the browser.
// Server Component (default in frameworks like Next.js)
export default async function Posts() {
  const posts = await db.posts.findMany();
  return posts.map(p => <h2 key={p.id}>{p.title}</h2>);
}

Add "use client" at the top of a file only when you need state, effects or click handlers. Server Components need a supporting framework such as Next.js.

Docs: Server Components

← Custom HooksLazy Loading →

Topic 6

Lazy Loading and Code Splitting in React Applications

Code splitting breaks one large JavaScript file into smaller pieces. Lazy loading downloads a piece only when the user needs it, so the first page opens faster.

One big bundle loads slowly while split bundles load the home page first and other pages on demand One big bundle Split bundles Home: loads now Dashboard: on click Settings: on click Smaller first download means a faster first screen
Red bar: everything at once. Green bar: just what the first screen needs.
const Dashboard = lazy(() => import("./Dashboard"));

<Suspense fallback={<p>Loading...</p>}>
  <Dashboard />
</Suspense>

Split by route first, since users only see one page at a time. Always give Suspense a fallback.

Docs: lazy · Suspense

← Server ComponentsError Boundaries →

Topic 7

Error Boundaries in React: Handling Errors Gracefully

An error boundary catches errors that happen while rendering its children and shows a fallback screen, so one broken widget does not crash the whole app.

A widget throws an error, the error boundary catches it and shows a fallback while the rest of the app keeps working App Header: fine ErrorBoundary Widget throws! shows fallback
The red dot travels up from the failing widget and stops at the boundary.
class Boundary extends React.Component {
  state = { failed: false };
  static getDerivedStateFromError() { return { failed: true }; }
  render() {
    return this.state.failed ? <p>Something went wrong.</p> : this.props.children;
  }
}

Boundaries do not catch errors in event handlers, async code or the boundary itself. Use try/catch there. The react-error-boundary package gives a ready-made version.

Docs: Error boundaries

← Lazy LoadingConcurrent Rendering →

Topic 8

React Concurrent Rendering Explained in Simple Terms

Concurrent rendering lets React pause a big, slow update to handle something urgent, like typing, first. Your app stays responsive while heavy work finishes in the background.

A long list render is paused when the user types, then resumes after the urgent update is shown Urgent: typing Heavy: big list Heavy work pauses, the keystroke appears instantly, then work resumes
The orange bar never blocks the green keystroke.
const [isPending, startTransition] = useTransition();

function onChange(e) {
  setText(e.target.value);                      // urgent
  startTransition(() => setList(filter(e.target.value))); // can wait
}
  • useTransition marks an update as low priority.
  • useDeferredValue gives you a delayed copy of a value.

Docs: useTransition · useDeferredValue

← Error BoundariesFAQ →

Frequently asked questions

What is the fastest way to speed up a slow React app?

Measure first with the Profiler. Then reduce unnecessary re-renders, keep state close to where it is used, split code with React.lazy, and virtualize long lists. See Topic 1.

What is the difference between useMemo and useCallback?

useMemo caches a calculated value. useCallback caches a function. See Topic 2.

Should I use Context API or Redux Toolkit?

Context for small, rarely changing values. Redux Toolkit for large, often-updated state. See Topic 3.

What are React Server Components?

Components that render on the server and send finished output, so users download less JavaScript. See Topic 5.