awesome-everything RU
↑ Back to the climb

Browser & Frontend Runtime

React fiber: code reading

Crux Read real React snippets — an index-key reorder bug, a render-phase side effect, a misplaced priority split, and a defeated bailout — and pick the fix a senior would make.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at senior altitude — in orbit
◷ 14 min

Fiber bugs are read in the code and in the Profiler, not in the docs. Read each snippet, predict how the reconciler treats it, and choose the change a senior engineer would make first.

Goal

Practise the loop you run in every React performance or correctness incident: read the component, predict how reconciliation, the render/commit split, and the lane scheduler handle it, then reach for the highest-leverage fix.

Snippet 1 — the reorderable list

function TodoList({ todos }) {
  // todos can be reordered by drag, and each row has an
  // uncontrolled <input> the user types notes into
  return (
    <ul>
      {todos.map((todo, i) => (
        <li key={i}>
          <span>{todo.title}</span>
          <input type="text" placeholder="notes…" />
        </li>
      ))}
    </ul>
  );
}
Quiz

A user types notes into row 3, then drags row 1 to the bottom. The notes appear to jump to the wrong row. What is the bug and the fix?

Snippet 2 — work in the function body

function Chart({ points }) {
  // build a derived dataset and log an analytics event
  const series = expensiveTransform(points);
  analytics.track('chart_rendered', { count: series.length });

  return <svg>{series.map(p => <Dot key={p.id} {...p} />)}</svg>;
}
Quiz

Which line is a latent bug under React 18 concurrent rendering, and why?

Snippet 3 — the priority split

function Search({ allItems }) {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState(allItems);
  const [isPending, startTransition] = useTransition();

  function onChange(e) {
    startTransition(() => {
      setQuery(e.target.value);                          // (A)
      setResults(filter(allItems, e.target.value));      // (B)
    });
  }
  return <><input value={query} onChange={onChange} />{isPending && <Spinner/>}<List items={results}/></>;
}
Quiz

Typing feels laggy even though the expensive filter is inside startTransition. What is wrong with this priority split?

Snippet 4 — the defeated bailout

const Row = React.memo(function Row({ item, onSelect }) {
  return <li onClick={() => onSelect(item.id)}>{item.label}</li>;
});

function List({ items, onSelect }) {
  return (
    <ul>
      {items.map(item => (
        <Row key={item.id} item={item} onSelect={() => onSelect(item.id)} />
      ))}
    </ul>
  );
}
Quiz

Every Row re-renders whenever List re-renders, even though React.memo wraps Row and the items are unchanged. Why, and what is the minimal fix?

Recap

Four fiber-level reads: an index key follows position, so uncontrolled state on a fiber drifts to the wrong item on reorder — use a stable id; a side effect in the function body runs an unpredictable number of times under replay — move it to useEffect or the event; the urgent input value must stay out of startTransition while only the expensive update goes in; and an inline arrow prop is a fresh reference every render that silently defeats React.memo. Read the code, predict how the reconciler treats it, fix the identity or the reference before reaching for any other lever.

Continue the climb ↑React fiber: tame a re-render storm
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.