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
Completed
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?
Heads-up Uncontrolled inputs reorder correctly with a stable key. The defect is the positional key, not the absence of a value prop — making it controlled is a different change that also requires per-row state.
Heads-up No effect can fix mismatched identity; the inputs are already attached to the wrong fibers by the time any effect runs. The fix is upstream, in the key, so reconciliation pairs fibers with the right todos.
Heads-up Memoising the JSX does not change how reconciliation matches children — it still keys by i. The identity problem is the key itself, not how often the array is rebuilt.
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
Completed
Which line is a latent bug under React 18 concurrent rendering, and why?
Heads-up Pure computation in render is allowed; if it is slow, you memoise it with useMemo, but it is not a correctness bug. The correctness bug is the impure analytics call, which produces observable effects on every replay.
Heads-up Spreading props is fine and does not affect reconciliation identity, which is driven by the key. It has nothing to do with the render-purity violation.
Heads-up React 18 explicitly does not guarantee one call per update — render can be replayed or discarded. That is precisely why side effects in the function body are unsafe.
Typing feels laggy even though the expensive filter is inside startTransition. What is wrong with this priority split?
Heads-up startTransition can wrap any number of updates. The problem is which updates belong there: the urgent input value must not be deferred, while the expensive list update should be.
Heads-up startTransition does put the update in the time-sliced transition lane. The lag is not about which API; it is that the urgent query update was wrongly placed in the low-priority lane.
Heads-up isPending is derived by React from the pending transition; you do not gate setResults on it. The spinner renders fine — the actual defect is the deferred input value.
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?
Heads-up React.memo works on any function component regardless of what it renders. It is being defeated by the unstable inline arrow prop, not by the element type.
Heads-up The key is correct and required — it is what gives each row stable identity. Removing it would cause warnings and worse reconciliation. The defeat is the inline function prop, not the key.
Heads-up Row is memoised on its own props (item, onSelect), not on the parent's items array. Even if items is new, each item reference can be stable; the real culprit is the fresh onSelect arrow created per row.
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.