React Render and Commit Phases

React separates calculating what the UI should look like from applying the resulting changes to the DOM. This render/commit split is fundamental to understanding how React can schedule rendering work, including in concurrent rendering.

The render phase is when React calculates the next UI. It calls components and compares the resulting React element tree with the previous one to determine what needs to change. Rendering should be treated as a pure calculation: component code should not directly mutate the DOM or perform other side effects that must happen exactly once.

The commit phase is when React applies the necessary changes to the host environment, such as updating DOM nodes in a browser. After React commits the update, the browser can display the resulting DOM changes. Commit work is not simply another component render; it is the stage where React makes the calculated changes take effect.

A state update can cause React to render a component and relevant descendants even when the final DOM change is small or nonexistent. React may also perform rendering work more than once or abandon a render before committing it, particularly with concurrent rendering. Code that depends on a render definitely being committed should therefore not run as an ordinary render-time side effect.

Effects are associated with the post-commit part of the update lifecycle. For example, `useEffect` is intended for synchronizing with external systems after React has committed, while `useLayoutEffect` runs after DOM mutations but before the browser paints. These hooks should not be confused with the render phase itself.

Understanding the boundary helps explain why React components should be pure and why DOM manipulation belongs in appropriate effects or refs rather than directly in component rendering. The key question is whether code is calculating the UI or making an external change based on the committed UI.

Key points

Interview questions

Why can React render a component without changing the DOM?

A state or parent update can cause React to evaluate components and produce a new element tree even when the resulting output is effectively the same. React compares the new result with the previous tree and determines what host changes are necessary. If no relevant DOM changes are needed, the commit can contain little or no DOM mutation. Therefore, rendering and DOM mutation are separate concepts.

What are React's render and commit phases?

The render phase is where React calls components and determines what the next UI should be. React then enters the commit phase and applies the required changes to the DOM. Rendering is primarily a calculation and should be pure, while committing is where the calculated changes take effect. A render does not necessarily mean that the DOM will change.

Why must component render functions avoid side effects?

React may render components more than once, and concurrent rendering can pause, restart, or abandon rendering work before it is committed. A side effect performed during rendering could therefore happen even though that render never becomes visible. Pure rendering makes repeated or discarded calculations safe. External synchronization should instead use mechanisms such as effects or event handlers.

How do render and commit phases relate to concurrent rendering?

Concurrent rendering allows React to work on rendering without requiring that every unit of rendering work immediately become visible. React can pause, resume, restart, or abandon rendering work when scheduling requires it. Once React has a result that it intends to show, it performs a commit to apply the corresponding host changes. This separation is why render logic must tolerate being evaluated without assuming that its result will be committed.

When would you choose `useLayoutEffect` instead of `useEffect`?

`useLayoutEffect` is useful when code must observe or synchronously adjust the DOM after React has applied mutations but before the browser paints. This can be important for layout measurement or preventing visible intermediate states. `useEffect` is preferred for most synchronization with external systems because it does not generally need to block painting. Neither hook should be used as a substitute for keeping render logic pure.