In React Native's Fabric renderer, what happens in the render, commit and mount phases after a component's state changes?
answer
- shadow nodes for host components only
- clone the path, share the rest
- Yoga runs in commit
- next tree gets promoted
- diff becomes view mutations
basics
~20 sRender clones the changed host components' shadow nodes into a new immutable tree. Commit runs Yoga layout and promotes it as the next tree. Mount diffs it against the tree on screen and applies only the resulting mutations to native views.
solid answer
~40 sIn **render**, React re-runs the affected components and Fabric clones the shadow nodes of the changed host components, plus their ancestors, into a new immutable shadow tree; unchanged subtrees are shared. In **commit**, Yoga computes size and position for every node (text is measured by the platform) and the laid-out tree is promoted as the next tree to mount. In **mount**, the renderer diffs the next tree against the previously rendered one in C++, producing atomic mutations such as create, insert, update, remove and delete, flattens layout-only views, promotes the tree, and applies the mutations to host views. Only the diff reaches native views, and intermediate trees can be skipped if several commits land before a mount.
go deeper
Name the three phases in order and say in one line what each produces: a new shadow tree, a laid-out tree, and changes to native views.
Explain structural sharing in render, what commit's layout and promotion do, and how mount's diff becomes a short list of view mutations.
Use the pipeline to reason about cost: which updates clone many nodes, which force layout of large subtrees, and why skipped intermediate trees reduce visible flicker.
Relate immutable trees to the concurrency and consistency guarantees they buy, and to the memory and cloning costs a very large screen pays for them.
## The three phases When a component's state changes, React Native's **Fabric** renderer moves the update through three phases. Each has one job, and each produces something the next one consumes. 1. **Render**: React re-runs the affected components and produces new elements. For every **host component** among them (`View`, `Text`, `Image`, anything backed by a native view) the renderer creates or clones a C++ **shadow node**. Your own function components never get a shadow node; only host components do. The result is a new **shadow tree**. 2. **Commit**: the renderer runs **Yoga** layout over the new tree to compute every node's size and position, then **promotes** the tree to be the "next tree" to mount. 3. **Mount**: the renderer **diffs** the next tree against the tree currently on screen, turns the difference into a list of view mutations, and applies them to the **host views**. ## Render: cloning, not mutating The shadow tree is **immutable**. To change a node, the renderer creates a new tree rather than editing the old one, and it keeps that cheap with **structural sharing**: - only nodes whose props, style or children changed are cloned; - every ancestor on the path from a changed node up to the root is cloned too, because its children changed; - every untouched subtree is shared between the old and the new tree. So a background color change deep in a screen clones a handful of nodes, not the whole tree. Immutability is also what lets React keep more than one version of the UI in progress, which concurrent features such as Transitions and Suspense rely on. ## Commit: layout and promotion **Layout calculation** needs two inputs: each node's style, which came from React, and the constraints of the root (how much space the surface has). Most of it runs entirely in C++. Some components cannot be sized by Yoga alone: text and text inputs depend on the platform's fonts and text engine, so for those Yoga calls into platform code to measure them. **Tree promotion** then marks the new, fully laid-out tree as the next one to mount. Nothing on screen has changed yet. ## Mount: diff, promote, apply Mounting has three steps: | Step | What it does | |---|---| | **Tree diffing** | Compares the previously rendered tree with the next tree in C++ and produces atomic mutations: create, delete, insert, remove, update. View flattening happens here too. | | **Tree promotion** | Atomically makes the next tree the "previously rendered" tree, so the following mount diffs against the right baseline. | | **View mounting** | Applies the mutations to the platform views on the UI thread. | Two consequences are worth stating in an interview: - **Only the diff is applied.** If only one view's `backgroundColor` changed, mounting issues a single update for that view; every other host view is left alone. - **Intermediate trees can be skipped.** The diff can be computed between whatever is mounted and whatever is newest, so if several commits happen before the next mount, the renderer does not have to mount each one. ## A worked example A note card toggles its pinned state: - **Render**: the card's `View` gets a new `backgroundColor`; the renderer clones that shadow node and its ancestors, and shares every other node. - **Commit**: a background color changes no size or position, so the layout results stay the same, and the tree is promoted. - **Mount**: the diff finds one update mutation, setting the background of one host view, and applies it. If the toggle also added a pin icon, the diff would contain a create and an insert for the icon's view, and layout would change for its siblings. ## Where the details live Which thread runs each phase, and when the whole pipeline can run synchronously on the UI thread, is a separate topic. So is React's own scheduling of when a render starts. The phases themselves are what the question asks for: **render builds an immutable shadow tree, commit lays it out and promotes it, mount diffs it and applies only the changes to native views.**
- In React Native's Fabric renderer, why does a custom function component never get a shadow node?Shadow nodes exist to become host views, and only host components such as View, Text and Image map to native views. React reduces your components by calling them until only host elements remain, so a component like NoteCard contributes the host components it returns, not a node of its own. That is also why native measurement methods are available on host refs and not on your components.
- In React Native's Fabric renderer, what happens if several commits land before the next mount?The renderer can skip the intermediate trees. The diff can be computed between the tree currently mounted and the newest committed tree, so the mount applies one combined set of mutations instead of replaying every intermediate version, and the user never sees those states.
saying these in an interview costs you the question
- Every render mutates the existing shadow tree in place.
- A state change re-creates every host view on the screen.
- Yoga layout runs during mount, after views are created.
- Each custom component gets its own shadow node and host view.
- Every committed tree must be mounted, one after another.