skip to content

React keeps two kinds of internal objects for your UI: React elements and fiber nodes. What is each one, and which of them survives from one render to the next?

level: middleimportance: must knowfreq 52%

answer

  1. one is a value, one is an identity
  2. recreated every render vs created once
  3. where does the state actually hang?
  4. first child, next sibling, back to parent
  5. description in, instance updated

basics

~20 s

A React element is a throwaway plain object describing what you want at a position: type, props, key. A fiber is React's long-lived internal node for that position, holding state, work flags and the DOM handle. Elements are recreated each render; fibers persist.

solid answer

~40 s

A React element is the *description*: a plain object with a `type`, a `props` object and an optional `key`, produced fresh on every render and discarded straight afterwards. A fiber is the *instance record*: React's internal node for one position in the tree, holding that position's state, the flags describing what work it needs, and a reference to the real DOM node when it has one. Fibers are linked to each other rather than nested — each has a pointer to its first child, its next sibling and its parent — so React can walk the tree without recursion. The practical consequence is the one interviewers are listening for: because the fiber survives, state survives. Your component function re-running does not reset anything; only losing the fiber does.

go deeper

for a junior

Recall the one-line distinction: elements are the descriptions your component returns each render, fibers are React's internal nodes that stick around and remember state.

for a middle

Explain the lifecycle of each object — an element is created, consumed and discarded within a single render, while React reuses the fiber at that position and records what work it needs.

for a senior

Use the distinction to explain real behaviour: why re-rendering is not remounting, why state disappears only when a position is removed, and why comparing element objects tells you nothing useful.

for a principal

Be clear about the boundary between internals and contract. Naming fiber fields demonstrates depth, but you should set the team rule that no production code depends on them, since they are unstable across React releases.

## Two objects, two jobs It is easy to say "React builds a tree of elements" and stop there, but React actually maintains two distinct structures, and almost every confusing behaviour becomes obvious once you can tell them apart. **A React element is a description.** It is a plain object with a `type` (a string like `'div'` for a host element, or the component function itself), a `props` object, and an optional `key`. It is created when your component runs, it is immutable — in development React even freezes it — and it is garbage the moment React has finished looking at it. An element does not know whether it has been rendered before, what state belongs to it, or which DOM node it produced. It is a value, not an identity. **A fiber is a record of an instance.** For every position that React has actually mounted, there is a fiber node holding the durable facts about that position: the component type it represents, its current props, its state, the flags describing what React must do to it on this update, and — for host components — the real DOM node in a field React calls `stateNode`. Fibers are created on mount and reused across renders. They are React's memory. ## Descriptions flow in, instances persist The render cycle reads as a conversation between the two. Your component runs and returns elements. React walks the existing fiber tree in parallel with the new elements, and for each position asks: is there already a fiber here that this element can update? If yes, it reuses that fiber and records what changed. If not, it creates one. If the new description has nothing at that position, the fiber goes away, and everything it was holding — state, effects, the DOM node — goes with it. So a re-render does not "rebuild the component". It rebuilds the *description* of the component and hands it to a node that already exists. ## The pointers: child, sibling, return One detail that surprises people is that the fiber tree is not an object with a `children` array. Each fiber has three links: ```javascript // conceptual shape of a fiber's structural links { child: /* first child fiber, or null */ null, sibling: /* next fiber at the same level, or null */ null, return: /* parent fiber, or null at the root */ null, } ``` A parent points only at its *first* child; the rest of the children are reached by following `sibling` from there. `return` points back up — it is called `return` rather than `parent` because it is where React goes when it has finished with a node, the way a function returns to its caller. This is a singly linked structure, and the reason it exists is that a position in it can be captured as a single pointer. Walking the tree becomes a loop over "next unit of work" rather than a recursive descent whose position lives on the JavaScript call stack. ## Why the split matters in practice Three everyday behaviours fall directly out of this design. First, **state survives re-renders because the fiber does**. A function component body re-running from the top does not reset `useState`, because the values were never in the function body — they are on the fiber. Second, **elements are worthless to compare by identity**. Every render produces brand-new element objects; two renders never share one. Any reasoning about "did this change?" has to be about the values inside the props, not about the element object. Third, **props on a fiber lag the props you just returned**. During an update, React distinguishes the props it has committed from the incoming ones; that is why React can describe both "what is on screen" and "what we are trying to make true" without confusing them. ## The names, and the caution that goes with them Field names like `child`, `sibling`, `return`, `stateNode` and `memoizedState` are real, but they belong to React's internals, not to its public API. It is fine — often impressive — to name them in an interview to show you have read the reconciler. It is not fine to build application code that reaches into them: they are unstable by design and can change between releases. Everything you legitimately need is exposed through hooks, refs and the component model itself. ## The compressed answer "Elements are immutable descriptions produced on every render and thrown away; fibers are React's persistent per-position nodes holding state, flags and the DOM handle, linked child/sibling/return so React can traverse them iteratively. Your state lives on the fiber, which is why re-rendering doesn't reset it."

  • If elements are recreated on every render, why does comparing two element objects with === almost always return false?
    Because each render allocates brand-new objects. Even when nothing changed, the previous element and the new one are two distinct allocations describing the same thing, so reference comparison fails. Any meaningful "did it change" question has to look at the values inside props, which is exactly the comparison React itself performs when it reconciles a position.
  • What happens to a fiber's state when its position disappears from the returned output?
    The fiber is removed and everything it held goes with it — hook state, refs and the DOM node it managed. There is no cache that restores it if the same component reappears later; it mounts fresh with initial state. Persisting anything across that boundary requires storing it somewhere that outlives the fiber, such as a parent or an external store.
  • Why does a fiber hold a reference to the real DOM node rather than React looking it up when needed?
    Because reconciliation runs over positions, not selectors. Keeping the node on the fiber means that once React decides a position needs an attribute or text change, applying it is a direct property write with no query, no traversal and no dependence on the document's current shape. It also lets React attach and detach refs precisely, since it already knows which node belongs to which position.

saying these in an interview costs you the question

  • Saying elements are DOM nodes React keeps in memory
  • Thinking a re-render creates a new component instance
  • Assuming state is stored inside the component function's closure
  • Treating element objects as stable identities across renders
  • Claiming the fiber tree stores children in a plain array

context