React Component will not update until it scheduled, Why? it explain here.
Let’s look at a deceptively simple but often confusing React example.
const App = () => {
const countRef = useRef(0);
function handle() {
countRef.current++;
}
return (
<>
{countRef.current}
<button onClick={handle}>Update</button>
</>
);
};
Question: Why does {countRef.current} NOT change when the button is clicked?
At first glance, it feels like it should update. The value is clearly changing in memory. To understand why the UI does not update, we need to think in terms of React Fiber and the reconciliation process.
A Quick Reminder: How React Rendering Works
I won’t go deep here, assuming you already understand React’s render cycle. But one key idea matters:
React only re-renders when an update is scheduled.
No scheduled update = no reconciliation = no DOM update.
Why useRef Does Not Trigger a Re-render
The real question is not “Why doesn’t useRef work?” The real question is:
Why does React not schedule a render when useRef changes?
Unlike useState, useRef is not part of React’s update system.
When you call setState, React does a lot of work behind the scenes:
This entire pipeline is what makes UI updates possible.
What Actually Happens with useRef
Now compare that with this line:
countRef.current++;
Here’s what React does NOT do:
So the result is simple:
The component does not re-render, and the DOM stays the same.
The Same Rule Applies to Other Hooks Too
This behavior is not unique to useRef.
Hooks like these also do not schedule renders by themselves:
They all update memory or perform side effects, but they do not mark a Fiber as dirty.
Because of that:
The Mental Model That Finally Makes It Click
Think of useRef as:
“Mutable memory attached to a component” not “State that affects rendering”
useRef is perfect for:
But it is not meant to drive UI updates.
If the UI must change → use useState (or a reducer). If you just need memory → useRef is your tool.
Final Thought
React Fiber is extremely intentional about when and why it re-renders. useRef bypasses the scheduling system on purpose — and that’s not a bug, it’s a feature.
Once you see useRef as memory, not state, this behavior makes perfect sense.
Thank you