Skip to solution
hardSystem Design

How does React Fiber work?

137 views
01

Understand the problem

Question presented to candidate: "React Fiber is described as a rewrite of the reconciler. What actually changed, and why?"

What a strong answer should cover:

  • Fiber is React's internal representation of a unit of work — one JavaScript object per element in the tree, plus the reconciler that walks them.
  • The problem it solved: the old reconciler used recursion, so a render could not be interrupted. Once started, it ran to completion and blocked the main thread.
  • Fiber replaces recursion with a linked-list tree — each node has child, sibling and return pointers — which turns the traversal into a loop over an explicit structure rather than a call stack.
  • Because the position is data rather than stack frames, React can stop between units, yield to the browser, and resume later — that is what makes concurrent features possible.
  • Double buffering: React keeps a pair of fibers per position (current and alternate), building the next tree into the spare one, so the committed tree is never partially mutated.
  • Two phases: the render phase is interruptible and produces a list of effects; the commit phase is synchronous and applies them.
  • Each fiber carries memoizedState (the hooks linked list), memoizedProps, flags (what changed) and lanes (priority).
  • Fiber is an implementation detail — do not reach into it in application code.

Clarifying questions expected:

  • "Do you want the data structure, or the scheduling consequences?" — they are separable answers.

Code / implementation expected: No. Fiber is internal; describing the structure and what it enables is the answer.

fiberarchitecturereconciliation
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: Engineers preparing for senior React interviews — assumes reconciliation basics. Difficulty: Hard

How to read this doc: Concepts are explained in plain language first, then tagged with 📌 Interview term:. Sections 3 and 5 are **actual fiber nodes read out of a running React

Solution ready — 2 min read

Classified // press E to declassify

04

Explore the playground snippets

Reading a real fiber off a DOM node and walking its pointers
Run Playground
import { useState, useRef } from "react";

// NOTE: this reaches into a React INTERNAL to make the structure visible.
// Never do this in application code — the property name is deliberately
// randomised, the shape changes between versions, and none of it is public.
function fiberOf(node) {
  const key = Object.keys(node).find((k) => k.startsWith("__reactFiber$"));
  return key ? node[key] : null;
}

const nameOf = (f) =>
  !f ? "null" : typeof f.type === "function" ? (f.type.name || "anonymous") : String(f.type);

function Leaf() {
  return <span>leaf</span>;
}

export default function App() {
  const probe = useRef(null);
  const [n, setN] = useState(0);
  const [out, setOut] = useState([]);

  const inspect = () => {
    const fiber = fiberOf(probe.current);
    if (!fiber) return setOut(["no fiber found — React internals may have changed"]);

    // Walk the children: child, then follow sibling. There is no array.
    const kids = [];
    for (let c = fiber.child; c; c = c.sibling) kids.push(nameOf(c));

    setOut([
      "fiber.tag:    " + fiber.tag + "   (5 = host component, a real DOM element)",
      "fiber.type:   " + JSON.stringify(fiber.type),
      "",
      "children, reached via child -> sibling:",
      "  " + kids.join(" -> "),
      "parent, reached via return:",
      "  " + nameOf(fiber.return),
      "",
      "alternate:                    " + (fiber.alternate ? "a paired fiber" : "null (none yet)"),
      "alternate.alternate === it?   " + (fiber.alternate ? String(fiber.alternate.alternate === fiber) : "n/a"),
      "",
      "fields present: " +
        ["child", "sibling", "return", "memoizedState", "memoizedProps", "alternate", "flags", "lanes"]
          .filter((f) => f in fiber)
          .join(", "),
    ]);
  };

  return (
    <div style={{ padding: 24, fontFamily: "system-ui", lineHeight: 1.6, maxWidth: 600 }}>
      <div style={{ display: "flex", gap: 8, marginBottom: 12 }}>
        <button onClick={inspect}>read the fiber</button>
        <button onClick={() => setN((v) => v + 1)}>re-render ({n})</button>
      </div>

      {/* The node whose fiber we read. It has two children of different kinds. */}
      <div ref={probe} id="probe" style={{ border: "1px dashed #aaa", borderRadius: 8, padding: 10 }}>
        <Leaf />
        <b> · render count {n}</b>
      </div>

      <pre style={{ background: "#f6f6f8", padding: 10, borderRadius: 8, fontSize: 12, marginTop: 12, minHeight: 190 }}>
{out.length ? out.join("\n") : "press 'read the fiber'"}
      </pre>

      <p style={{ fontSize: 13, color: "#666" }}>
        Read it once, then press re-render and read it again: <code>alternate</code>
        starts as null and appears after the first update — React allocates the
        second buffer lazily. Note there is no children array anywhere; the
        second child is reached by following <code>sibling</code>.
      </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 117 of 119 decoded in the React.js track. One more won't hurt.

Back to track