Why React Cares So Much About āPureā Rendering
React keeps rendering pure, meaning components only describe UI without causing side effects. This allows React to safely re-render or discard work without bugs. Side effects are handled separately using useEffect to keep everything predictable.
Thereās a moment when learning React where something starts to feel⦠restrictive.
You try to fetch data, set up something, or run a piece of logicāand suddenly youāre told:
āDonāt do that here. Use useEffect.āAt first, it feels like React is just being annoying.
Why canāt we just run things when the component is about to mount? Why must everything wait until after render?
The answer sits in one idea that React takes very seriously:
rendering should be pure.
What āPureā Actually Means
When React calls your component, it expects one thing:
function Component() {
return <div>Hello</div>
}Given the same inputs (props, state), it should always return the same output.
No surprises. No hidden behavior.
Thatās what āpureā means here.
Where It Starts to Break
Now imagine doing this inside your component:
function Component() {
fetch("/api/data")
return <div>Hello</div>
}It might work⦠but something feels off.
Because now your render is doing more than just describing UI.
Itās:
- triggering a network request
- causing side effects
- interacting with something outside React
Thatās no longer pure.
Why React Doesnāt Allow This
The problem isnāt just about āclean codeā.
Itās about how React actually runs your component.
React doesnāt guarantee that a render will always be used.
It can:
- render a component
- pause it
- throw it away
- render again
This happens in modern React with things like concurrent rendering.
Now Imagine This Scenario
function Component() {
fetch("/api/data")
return <div>Hello</div>
}React:
- renders ā API call happens
- discards render
- renders again ā API call happens again
You now have:
- duplicate requests
- inconsistent behavior
- bugs that are hard to trace
This Is Why Purity Matters
By keeping render pure, React ensures:
- no side effects during render
- no accidental duplication
- predictable behavior
Rendering becomes something React can safely run multiple times.
So Where Do Side Effects Go?
Thatās where useEffect comes in.
useEffect(() => {
fetch("/api/data")
}, [])Now the flow is different:
- React renders
- DOM updates
- Effect runs
This guarantees:
- the component is actually mounted
- the work is not wasted
- the side effect runs at the right time
The Trade-off
You lose something:
- you canāt run logic ābefore renderā
But you gain something more important:
- consistency
- safety
- control in a more predictable way
A Better Way to Think About It
Instead of asking:
āWhen should this run in the lifecycle?ā
Think:
āIs this part of rendering, or is this a side effect?ā
If it affects the outside world:
- API calls
- timers
- event listeners
- third-party libraries
It doesnāt belong in render.
Why This Design Feels Different
If youāve used frameworks like Vue, this can feel limiting.
Youāre used to hooks like:
beforeMountmounted
Where you can control exactly when things happen.
React takes a different approach.
It removes that control in exchange for stronger guarantees.
The Core Idea to Keep
Rendering is just a description.
It should not:
- change anything
- trigger anything
- depend on external effects
It should only answer:
āWhat should the UI look like right now?ā
Final Takeaway
The restriction isnāt there to make things harder.
Itās there to make React reliable.
Once you accept that rendering is pure, everything else starts to fall into place:
- why
useEffectexists - why thereās no
beforeMounted - why React can re-render freely
And most importantly:
why your UI stays predictable even as your app grows