DEV Community

Cover image for What Really Happens When React State Changes?
Tanu Priya
Tanu Priya

Posted on

What Really Happens When React State Changes?

You write:

const [count, setCount] = useState(0);
Enter fullscreen mode Exit fullscreen mode

Then the user clicks a button:

setCount(count + 1);
Enter fullscreen mode Exit fullscreen mode

And suddenly:

Count: 0
Enter fullscreen mode Exit fullscreen mode

becomes:

Count: 1
Enter fullscreen mode Exit fullscreen mode

It looks simple.

But what actually happens between calling setCount() and seeing 1 on the screen?

React doesn't immediately find the <h1> element and change its text.

Instead, the state update starts a series of steps that eventually lead to the browser displaying the new UI.

The simplified mental model is:

State Update → Render → Reconciliation → Commit → Browser
Enter fullscreen mode Exit fullscreen mode

Let's follow that process from beginning to end.


The Example

We'll use a simple counter:

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>Count: {count}</h1>

      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Initially, count is 0.

The user sees:

Count: 0

[ Increment ]
Enter fullscreen mode Exit fullscreen mode

When the button is clicked, this runs:

setCount(count + 1);
Enter fullscreen mode Exit fullscreen mode

So the state needs to change:

0 → 1
Enter fullscreen mode Exit fullscreen mode

What happens next?


1. The State Update Is Scheduled

The first thing to understand is that setCount() is not a DOM manipulation command.

When you write:

setCount(1);
Enter fullscreen mode Exit fullscreen mode

you're not telling the browser:

"Find the <h1> and change its text to 1."

You're telling React that the component's state has changed and that its rendered output may need to change.

That's a fundamentally different approach from imperative DOM manipulation.

For example, this is imperative:

document.querySelector("h1").textContent = "Count: 1";
Enter fullscreen mode Exit fullscreen mode

Here, you're directly telling the browser what to change.

With React:

setCount(1);
Enter fullscreen mode Exit fullscreen mode

you describe a state change, and React takes responsibility for determining the UI that should result from it.


2. React Renders the Component

After processing the state update, React needs to determine what the UI should look like with the new state.

Conceptually, our component now renders with:

count = 1
Enter fullscreen mode Exit fullscreen mode

So this:

<h1>Count: {count}</h1>
Enter fullscreen mode Exit fullscreen mode

produces:

<h1>Count: 1</h1>
Enter fullscreen mode Exit fullscreen mode

This is what we mean when we say the component re-renders.

And here's one of the most important React concepts:

A re-render does not mean the entire DOM is recreated.

React is calculating the component's next UI output. It isn't throwing away the existing browser DOM and rebuilding everything from scratch.

So:

Re-render ≠ DOM rebuild
Enter fullscreen mode Exit fullscreen mode

3. React Determines What Changed

Now React has a previous UI representation and a new one.

Previously:

Count: 0
Enter fullscreen mode Exit fullscreen mode

Now:

Count: 1
Enter fullscreen mode Exit fullscreen mode

The surrounding structure hasn't changed.

The <div> is still there.

The <h1> is still there.

The <button> is still there.

Only the displayed text has changed.

React's reconciliation process determines how the new element tree relates to the previous one and what work needs to be performed.

This is why reconciliation is often described as the process of figuring out what needs to change.

It's important not to think of this as React taking two snapshots of the browser DOM and comparing them.

React works with its own internal representations and reconciliation machinery to determine how the current tree should transition toward the next one.


4. React Commits the Changes

Once React has determined the work that needs to happen, it enters the commit phase.

This is where the required changes are applied to the host environment.

In a browser, that means updating the DOM.

For our counter, the result is effectively:

<h1>Count: 1</h1>
Enter fullscreen mode Exit fullscreen mode

The important thing is that React doesn't need to recreate the entire DOM structure just because the state changed.

The existing DOM can be updated where necessary.

So we can think of the process as:

State Update
     ↓
Render
     ↓
Reconciliation
     ↓
Commit
     ↓
DOM Update
Enter fullscreen mode Exit fullscreen mode

That's the core React mental model.


5. Then the Browser Has to Render It

React updating the DOM isn't quite the same thing as the user seeing pixels change.

The browser still has its own rendering work to perform.

A simplified version looks like:

DOM + CSS
   ↓
Style
   ↓
Layout
   ↓
Paint
   ↓
Composite
   ↓
Pixels
Enter fullscreen mode Exit fullscreen mode

So there are actually two different systems involved.

React determines and applies the UI changes.

The browser takes the resulting DOM, styles, and other rendering information and turns them into pixels.

This distinction becomes especially useful when you start learning about frontend performance.


6. Render Doesn't Always Mean DOM Changes

Here's another important misconception.

Suppose a component renders again.

That doesn't necessarily mean the browser DOM changes.

Imagine React renders the same output as before:

Previous:

<h1>Hello</h1>

Next:

<h1>Hello</h1>
Enter fullscreen mode Exit fullscreen mode

There may be no meaningful DOM mutation required.

So these are three different things:

Render
Reconciliation
DOM Update
Enter fullscreen mode Exit fullscreen mode

A render can happen without producing a DOM change.

That's why saying:

"The component rendered, so React changed the DOM."

isn't necessarily correct.


7. Why Does a Component Re-render?

State updates are one reason.

But they're not the only reason a component can render.

For example, a component may render because:

  • its state changed
  • its parent rendered
  • a context value it uses changed
  • an external store triggered an update
  • another React-driven update occurred

This is why the statement:

"React only re-renders when state changes."

is too simplistic.

The more useful question is:

What caused this component to render, and what work did that render actually perform?

That question becomes very important when debugging performance.


8. What About the Virtual DOM?

You've probably heard:

"React uses a Virtual DOM."

And you've probably also heard:

"The Virtual DOM is a copy of the real DOM."

That's a useful beginner explanation, but it's an oversimplification.

A better mental model is:

React maintains in-memory representations of the UI and uses them as part of its rendering and reconciliation process.

When state changes, React calculates the next UI and determines how it should transition from the current tree.

The important idea isn't:

Virtual DOM = faster DOM
Enter fullscreen mode Exit fullscreen mode

The more useful idea is:

You describe the UI.
React manages the transition.
Enter fullscreen mode Exit fullscreen mode

This is a major part of what makes React declarative.


9. Declarative vs Imperative

Consider an imperative approach.

You might manually update the DOM:

title.textContent = user.name;

if (user.isOnline) {
  status.textContent = "Online";
  status.classList.add("active");
} else {
  status.textContent = "Offline";
  status.classList.remove("active");
}
Enter fullscreen mode Exit fullscreen mode

Now your code needs to keep track of:

  • which element changed
  • what value it should have
  • which classes need to be added or removed
  • what happens when multiple pieces of state change

React lets you describe the desired UI instead:

<p>
  {isOnline ? "Online" : "Offline"}
</p>
Enter fullscreen mode Exit fullscreen mode

You describe the UI for the current state.

React handles the transition from the previous result to the next one.

That's the declarative model.


10. What Happens With Multiple State Updates?

Consider:

setName("Nayan");
setAge(25);
setLoading(false);
Enter fullscreen mode Exit fullscreen mode

It would be misleading to assume that React necessarily does this:

setName()
  ↓
render

setAge()
  ↓
render

setLoading()
  ↓
render
Enter fullscreen mode Exit fullscreen mode

React can batch state updates so that multiple updates are processed together when appropriate.

Conceptually:

Multiple Updates
      ↓
React processes them
      ↓
Render
      ↓
Reconciliation
      ↓
Commit
Enter fullscreen mode Exit fullscreen mode

This can reduce unnecessary work.

The exact behavior depends on the React version and execution context, but the important mental model is:

State setters are requests for React to update its rendered output, not direct DOM commands.


11. Does React Rebuild Everything?

No.

This is probably the most important misconception to eliminate.

Suppose a component contains:

return (
  <div>
    <h1>Welcome</h1>
    <p>{isOnline ? "Online" : "Offline"}</p>
    <button>Change Status</button>
  </div>
);
Enter fullscreen mode Exit fullscreen mode

If isOnline changes, the component may render again.

But that doesn't mean React throws away:

<div>
<h1>
<button>
Enter fullscreen mode Exit fullscreen mode

and creates completely new DOM elements for everything.

React's reconciliation process determines what changed and the commit phase applies the necessary updates.

So keep these distinctions in mind:

Component re-render
        ≠
Entire DOM recreated

Render
        ≠
DOM update

State update
        ≠
Direct DOM manipulation
Enter fullscreen mode Exit fullscreen mode

These distinctions will save you from a lot of confusion later.


12. Why Can Re-renders Still Be Expensive?

If React doesn't rebuild the entire DOM, does that mean re-renders are free?

Definitely not.

A render can still perform a lot of JavaScript work.

Imagine a component that:

  • renders thousands of elements
  • performs expensive calculations
  • processes a large dataset
  • creates many objects
  • triggers many child renders

Even if the final DOM change is tiny, the work required to calculate that result might be expensive.

That's why React performance optimization focuses on questions such as:

  • Where should state live?
  • Which components actually need to render?
  • Are expensive calculations being repeated?
  • Are unnecessary child renders happening?
  • Would React.memo help?
  • Would useMemo or useCallback actually solve a real problem?
  • Should a large list be virtualized?

The goal isn't:

"Prevent every re-render."

The goal is:

Avoid unnecessary expensive work.


13. The Complete Journey

Let's return to our original example:

setCount(count + 1);
Enter fullscreen mode Exit fullscreen mode

The user doesn't directly cause this:

setCount()
   ↓
DOM changes
Enter fullscreen mode Exit fullscreen mode

A better mental model is:

User interaction
      ↓
State update
      ↓
React renders
      ↓
Reconciliation
      ↓
Commit
      ↓
Browser rendering
      ↓
Pixels on screen
Enter fullscreen mode Exit fullscreen mode

For our counter, the visible result is simply:

Count: 0
     ↓
Count: 1
Enter fullscreen mode Exit fullscreen mode

But underneath that tiny change, React and the browser perform several steps to produce the final result.


The Mental Model You Should Remember

When you see:

setCount(count + 1);
Enter fullscreen mode Exit fullscreen mode

don't think:

"React changes the DOM."

Think:

"The state changed, so React needs to determine what the UI should look like now."

That leads to this mental model:

State changes
     ↓
React calculates the next UI
     ↓
React reconciles it
     ↓
React commits required changes
     ↓
Browser renders the result
Enter fullscreen mode Exit fullscreen mode

And remember these three rules:

1. State updates are not DOM commands

setState ≠ DOM manipulation
Enter fullscreen mode Exit fullscreen mode

2. Re-rendering does not mean rebuilding the entire DOM

Re-render ≠ DOM rebuild
Enter fullscreen mode Exit fullscreen mode

3. Rendering does not necessarily mean the DOM changes

Render ≠ DOM update
Enter fullscreen mode Exit fullscreen mode

Final Takeaway

React's core idea is surprisingly simple:

You describe what the UI should look like for a given state, and React manages the transition from the previous UI to the next one.

So the next time you write:

setCount(count + 1);
Enter fullscreen mode Exit fullscreen mode

remember that you're not telling the browser:

"Change this text to 1."

You're changing the state that drives your UI.

React then determines the next rendered result, reconciles it with the previous one, commits the necessary changes, and the browser eventually turns that result into pixels.

Top comments (0)