• React
    • Internals
    • Concepts

    Virtual DOM vs Real DOM in React

    By Published Updated 6 min read

    How React's virtual DOM, reconciliation and commit phase update the real DOM, and what Fiber and React 18 concurrent rendering changed.

    The real DOM is the browser's live tree of page elements, while the virtual DOM is a lightweight JavaScript description of what the UI should look like. When state changes, React renders a new description, compares it with the previous one, and updates only the parts of the real DOM that actually changed. The virtual DOM does not make DOM updates themselves faster; its value is letting you write UI declaratively while React works out which updates are necessary.

    Key takeaways

    • The real DOM is the browser's object model of the page, and changing it can trigger style, layout and paint work.
    • The virtual DOM is a tree of plain JavaScript objects (React elements) that your components return each time they render.
    • Reconciliation compares the new tree with the previous one, and the commit phase applies only the differences to the real DOM.
    • Keys help React match list items and component instances between renders.
    • React Fiber (React 16) made rendering interruptible in principle; concurrent rendering, released in React 18, put it to use.

    Why is "a faster copy of the DOM" an incomplete answer?

    "What is the virtual DOM?" is a common React interview question, and a common answer is: "It's a copy of the real DOM that updates faster."

    That answer is incomplete and slightly misleading. React still has to update the real DOM in the end, and building and comparing virtual trees is extra work on top of that. What the virtual DOM gives you is a way to describe the whole UI for any state, while React figures out the minimal set of real DOM changes. Let's look at what's happening under the hood.


    What is the real DOM, and why can updates be expensive?

    The real DOM (Document Object Model) is the browser's in-memory representation of the page. Plain JavaScript work, such as updating an object, is cheap. Changing the DOM can cost more, because the browser may then need to:

    1. Recalculate styles: Work out which CSS rules apply.
    2. Recompute layout: Calculate the position and size of affected elements.
    3. Repaint: Draw the updated pixels.

    These costs add up when a page makes many DOM changes. They get worse when code alternates between writing to the DOM and reading layout values such as offsetHeight, which forces the browser to recalculate layout again and again. That pattern is called layout thrashing, and it is a common reason heavy web apps feel laggy.


    What is the virtual DOM?

    The virtual DOM is a JavaScript object tree that describes what the UI should look like. It has no direct connection to the screen; it's just data. When you write JSX, it compiles into function calls that create these objects, which React calls elements.

    // A simplified virtual DOM node
    // (React's real element objects have more fields, and children live in props)
    const vNode = {
      type: "div",
      props: { className: "container" },
      children: ["Hello"]
    };
    

    When you call a state setter such as setCount, React does not touch the real DOM right away. Instead, the React docs describe three steps (React docs: render and commit):

    1. Trigger: The state update schedules a render.
    2. Render: React calls your component function, which returns a new tree of elements.
    3. Commit: React applies the necessary changes to the real DOM.

    How does React reconciliation work?

    Reconciliation is the process of comparing the new element tree with the previous one to work out what changed. React's documentation describes it as a heuristic O(n) algorithm built on two assumptions: elements of different types produce different trees, and keys identify which children stay stable across renders (legacy React docs: reconciliation).

    1. Different types? If a <div> becomes a <span>, or <Article> becomes <Comment>, React tears down that whole subtree and builds a new one. Any state inside it is lost.
    2. Same type? React keeps the existing DOM node and updates only the attributes that changed, such as className or src.
    3. Keys: In lists, keys tell React which item is which between renders. Changing a component's key makes React treat it as a brand-new instance, which is how you reset a component with the key prop.

    What happens in the commit phase?

    Once React knows what changed (for example, "this text changed from 'A' to 'B'"), it applies those changes to the real DOM during the commit phase. React only changes DOM nodes whose output differs between renders, and it leaves everything else alone.

    Keeping DOM writes to the necessary minimum limits how much style, layout and paint work the browser has to do.


    What did React Fiber and React 18 change?

    In older versions of React (the "stack reconciler"), rendering was synchronous. Once React started rendering a large tree, it could not stop until it finished, which could block the main thread and make animations or typing stutter.

    React Fiber, the rewrite of React's reconciler that shipped in React 16, splits rendering into small units of work called fibers. This architecture made interruptible rendering possible, but React 16 and 17 still rendered synchronously by default.

    Concurrent rendering arrived as a stable feature in React 18. In the React 18 release post, the team describes a key property of concurrent React: rendering is interruptible (React v18.0 announcement). With features such as startTransition and useDeferredValue, React can pause a non-urgent render to handle more urgent updates, such as typing or clicking, and then continue. This helps interfaces stay responsive during heavy updates, especially on slower devices.


    Summary

    1. The virtual DOM is a description: It's like a draft of your UI for the current state.
    2. Diffing: React compares the new draft with the previous one.
    3. Commit: React applies only the necessary changes to the real DOM.
    4. Let React own its DOM: Avoid changing DOM nodes that React manages with jQuery or document.getElementById. React doesn't know about those changes, so it can overwrite them, and the React docs warn this can lead to inconsistent results or crashes. Use refs when you need direct DOM access, such as focusing an input (React docs: manipulating the DOM with refs).

    See React in action in the React playground: render a list, update one item, and inspect the preview with your browser's developer tools to watch which DOM nodes change. To see how components use state and effects on top of this model, read React hooks explained for beginners.

    Frequently asked questions

    Is the virtual DOM faster than the real DOM?

    Not by itself. React still has to update the real DOM, and building and comparing virtual trees is extra work. The benefit is that you describe the whole UI declaratively while React works out which DOM changes are actually needed, avoiding many unnecessary updates without you writing that tracking code by hand.

    What is reconciliation in React?

    Reconciliation is the process React uses to compare the element tree from the latest render with the previous tree. It decides which components to keep, update or recreate, using element types and keys as hints. The resulting changes are then applied to the real DOM during the commit phase.

    Does React re-render the whole page when state changes?

    No. React re-renders the component whose state changed and, by default, the components inside it. It then compares the new output with the previous output and updates only the DOM nodes that differ. Components elsewhere in the tree do not re-render unless their own state, props or context change.

    What is React Fiber?

    React Fiber is the reconciler architecture introduced in React 16. It breaks rendering work into small units that React can prioritize, pause and resume. Fiber laid the groundwork for concurrent rendering, which became stable in React 18 through features such as transitions and deferred values that keep interfaces responsive during heavy updates.

    Try the examples yourself

    Open the React playground to run and edit code from this article in your browser. There is nothing to install and no account to create.