When Reactivity Is Too Much: Understanding shallowRef and shallowReactive in Vue
shallowRef and shallowReactive are Vue reactivity APIs that track only top-level changes, ignoring nested mutations, allowing more controlled and efficient state management.
Reactivity in Vue feels effortless.
You change somethingâand everything stays in sync.
But thereâs an assumption hidden in that convenience:
That everything should be reactive.
Every nested object.
Every property.
Every layer.
And most of the time, thatâs exactly what you want.
Until it isnât.
When Deep Reactivity Becomes a Problem
By default, Vue observes deeply.
If you create an object:
const state = reactive({
user: { name: "Rishi" }
})Vue doesnât just track state.
It tracks:
state.userstate.user.name
Every level becomes part of the system.
Which means any change, no matter how deep, can trigger updates.
This is powerful.
But it also means Vue is doing a lot of work behind the scenes.
And sometimes, that work isnât necessary.
A Different Kind of Control
This is where shallow reactivity comes in.
Instead of observing everything, Vue gives you a choice:
What if you only care about the surface?
Not whatâs insideâ
but when the container itself changes.
The Idea Behind shallowReactive
const state = shallowReactive({
user: { name: "Rishi" }
})Now, Vue watches only the top layer.
If you replace user, Vue reacts.
But if you change user.name directlyâ
nothing happens.
The structure is still there.
But Vue no longer follows every path inside it.
The Same Idea, Applied to Refs
const data = shallowRef({ count: 0 })Here, Vue tracks only:
data.value
Not what lives inside it.
So if you mutate:
data.value.count++Vue stays silent.
But if you replace the entire value:
data.value = { count: 1 }Then it reacts.
Because the outer reference changed.
What This Really Means
Shallow reactivity is not weaker.
Itâs more selective.
Youâre telling Vue:
âWatch this containerâbut donât worry about whatâs inside.â
And that changes how updates flow through your application.
Why This Exists
There are moments where deep reactivity is unnecessaryâor even harmful.
Large data structures can become expensive to track.
External libraries might behave unpredictably if wrapped in Proxies.
Sometimes, you only care about replacing a valueânot mutating it.
In these cases, deep observation becomes noise.
And shallow reactivity removes that noise.
A Shift in Perspective
With deep reactivity, every change matters.
With shallow reactivity, only structural changes matter.
That distinction is subtle.
But it changes how you think about state.
Instead of asking:
âWhat changed inside this object?â
You start asking:
âDid the reference itself change?â
Not Less PowerfulâJust More Intentional
Itâs easy to assume that shallow means limited.
But itâs really about control.
You decide how much Vue should observe.
How much it should care.
And how much work it should do.
A Final Thought
Reactivity in Vue is often described as automatic.
But itâs not meant to be thoughtless.
Sometimes, the best optimization is not making things fasterâ
but making fewer things matter.
And shallowRef and shallowReactive are reminders of that.
Not everything needs to be watched.
Only what truly matters.