Skip to solution
hardFrontend

React Compiler — how does auto-memoization work in React 19?

749 views
01

Understand the problem

Question presented to candidate: "React Compiler reached 1.0. What does it actually do to your code at build time, and does it mean you can delete every useMemo, useCallback, and React.memo in the codebase?"

What a strong answer should cover:

  • It is a build-time tool (a Babel plugin), not a runtime feature — it rewrites your components during compilation.
  • It performs automatic memoization: it infers what each component reads and produces, and caches values so they are only recomputed when their inputs change.
  • The output leans on a runtime hook — exposed on React as __COMPILER_RUNTIME.c, conventionally useMemoCache — which allocates a fixed-size cache array per component instance.
  • It relies on the Rules of React: components must be pure and props/state must not be mutated. Code that breaks those rules is skipped, not miscompiled.
  • It is opt-in and incremental; you can adopt it directory by directory.
  • Manual memoization is not forbidden and existing useMemo calls keep working — but they become largely redundant in compiled files.
  • Version precision: React Compiler 1.0 shipped on 7 October 2025, and it supports React 17 through 19.

Clarifying questions expected:

  • "Is the codebase already Rules-of-React clean — does it pass the ESLint rules?"
  • "Which build tool are we on? The integration differs for Next.js, Vite, and plain Babel."

Code / implementation expected: Optional. Being able to describe the before-and-after shape of a compiled component is worth more than writing one out.

react-compilerperformance
02

Attempt it yourself

Sketch your approach before reading the solution — that's what interviews test.

Nudge consolestandby

Stuck? Beam a request up — the console returns a conceptual nudge that guides your logic without spoiling the implementation.

03

Study the solution

Target Audience: Frontend engineers preparing for senior React interviews — assumes familiarity with useMemo and React.memo. Difficulty: Hard

How to read this doc: Concepts are explained in plain language first, then tagged with 📌 Interview term:. The runtime inspe

Solution ready — 2 min read

Classified // press E to declassify

04

Explore the playground snippets

Before and after: hand-written memoization the compiler would make redundant
Run Playground
import { useState, useMemo, useCallback, memo } from "react";

const ITEMS = Array.from({ length: 8 }, (_, i) => ({ id: i, n: (i * 37) % 11 }));

// A memoised child so the identity of its props actually matters.
const List = memo(function List({ items, onPick }) {
  console.log("List rendered");
  return (
    <ul>
      {items.map((it) => (
        <li key={it.id}>
          <button onClick={() => onPick(it.id)}>item {it.id} (n={it.n})</button>
        </li>
      ))}
    </ul>
  );
});

// WITHOUT the compiler you must write the memoization yourself, and every
// dependency array is a chance to get it wrong.
function Manual({ items }) {
  const [picked, setPicked] = useState(null);
  const [tick, setTick] = useState(0);

  const sorted = useMemo(() => items.slice().sort((a, b) => a.n - b.n), [items]);
  const onPick = useCallback((id) => setPicked(id), []);

  return (
    <section>
      <h4>Hand-written useMemo / useCallback</h4>
      <button onClick={() => setTick((t) => t + 1)}>Re-render parent ({tick})</button>
      <p>picked: {String(picked)}</p>
      <List items={sorted} onPick={onPick} />
    </section>
  );
}

// WITH React Compiler enabled you would write exactly this, and the build step
// would insert the equivalent caching — conceptually:
//   const $ = useMemoCache(4);
//   if ($[0] !== items) { $[1] = items.slice().sort(...); $[0] = items; }
function Plain({ items }) {
  const [picked, setPicked] = useState(null);
  const [tick, setTick] = useState(0);

  const sorted = items.slice().sort((a, b) => a.n - b.n);
  const onPick = (id) => setPicked(id);

  return (
    <section>
      <h4>Plain — what you write with the compiler on</h4>
      <button onClick={() => setTick((t) => t + 1)}>Re-render parent ({tick})</button>
      <p>picked: {String(picked)}</p>
      <List items={sorted} onPick={onPick} />
    </section>
  );
}

export default function App() {
  return (
    <div style={{ padding: 24, fontFamily: "system-ui", lineHeight: 1.5 }}>
      <Manual items={ITEMS} />
      <hr />
      <Plain items={ITEMS} />
      <p style={{ color: "#666", fontSize: 13 }}>
        Open the console. This playground has no compiler configured, so the
        Plain version re-renders List on every parent tick while the hand-memoised
        one does not. With the compiler enabled, both behave like the first.
      </p>
    </div>
  );
}
05

Join the discussion

Discussion (0)

Sign in to join the discussion.

No responses yet. Be the first to share what you think.

Transmission complete // awaiting log

KEEP THE
STREAK ALIVE.

Dossier 88 of 119 decoded in the React.js track. One more won't hurt.

Back to track