Shallow ref and shallow reactive help you track changes only on the top level of an object or array. This makes your app faster when you don't need to watch deep changes.
Shallow ref and shallow reactive in Vue
import { shallowRef, shallowReactive } from 'vue'; const myShallowRef = shallowRef(initialValue); const myShallowReactive = shallowReactive(initialObject);
shallowRef tracks changes only when the reference itself changes, not inside the object.
shallowReactive makes the top-level properties reactive but does not make nested objects reactive.
shallowRef holding an object. Changing properties inside user.value won't trigger updates, but replacing user.value with a new object will.import { shallowRef } from 'vue'; const user = shallowRef({ name: 'Anna', age: 25 }); // Changing user.value to a new object triggers updates user.value = { name: 'Ben', age: 30 };
settings.theme change is reactive, but changing options.fontSize inside the nested object is not reactive.import { shallowReactive } from 'vue'; const settings = shallowReactive({ theme: 'dark', options: { fontSize: 14 } }); settings.theme = 'light'; // reactive settings.options.fontSize = 16; // NOT reactive
This Vue app shows how shallowRef and shallowReactive behave. Only changes to the top-level object or properties trigger the watchers and console logs.
import { createApp, shallowRef, shallowReactive, watch } from 'vue'; const App = { setup() { const shallowUser = shallowRef({ name: 'Anna', age: 25 }); const shallowSettings = shallowReactive({ theme: 'dark', options: { fontSize: 14 } }); watch(() => shallowUser.value, () => { console.log('shallowUser changed'); }); watch(() => shallowSettings.theme, () => { console.log('Theme changed'); }); watch(() => shallowSettings.options.fontSize, () => { console.log('Font size changed'); }); // Change nested property inside shallowRef (no trigger) shallowUser.value.name = 'Ben'; // Replace shallowRef value (triggers) shallowUser.value = { name: 'Cara', age: 28 }; // Change top-level shallowReactive property (triggers) shallowSettings.theme = 'light'; // Change nested shallowReactive property (no trigger) shallowSettings.options.fontSize = 16; return {}; }, template: `<div>Check console for watch logs.</div>` }; createApp(App).mount('#app');
Use shallowRef when you want to track changes only when the whole object changes, not its inner parts.
Use shallowReactive when you want reactivity on top-level properties but want to ignore nested objects for performance.
Remember that nested changes inside shallow reactive objects or shallow refs do not trigger updates.
Shallow ref tracks changes only when the reference changes, not inside the object.
Shallow reactive tracks changes on top-level properties only, ignoring nested objects.
Use them to improve performance when deep reactivity is not needed.
Practice
shallowRef in Vue track reactively?Solution
Step 1: Understand shallowRef behavior
shallowReftracks reactivity only when the reference changes, not inside nested objects.Step 2: Compare with deep reactivity
Unlikereforreactive, it does not track nested property changes.Final Answer:
Only changes to the reference itself, not nested properties -> Option CQuick Check:
shallowRef tracks reference, not deep changes [OK]
- Thinking shallowRef tracks nested property changes
- Confusing shallowRef with reactive
- Assuming shallowRef tracks primitive values inside
Solution
Step 1: Identify shallow reactive syntax
shallowReactiveis used to create a shallow reactive object that tracks only top-level properties.Step 2: Differentiate from other APIs
reactivecreates deep reactivity,shallowRefandrefcreate refs, not shallow reactive objects.Final Answer:
const state = shallowReactive({ count: 0, nested: { value: 1 } }) -> Option BQuick Check:
shallowReactive creates shallow reactive objects [OK]
- Using reactive() instead of shallowReactive()
- Confusing shallowRef with shallowReactive
- Using ref() for reactive objects
const state = shallowReactive({ count: 0, nested: { value: 1 } });
state.nested.value = 2;
console.log(state.nested.value);What will be logged to the console?
Solution
Step 1: Understand shallowReactive behavior
shallowReactive tracks only top-level properties reactively, but nested objects still exist and can be mutated normally.Step 2: Check nested property assignment
Assigningstate.nested.value = 2changes the nested object property directly, so the value updates.Final Answer:
2 -> Option DQuick Check:
Nested objects update but are not reactive [OK]
- Assuming nested changes are not possible
- Expecting nested changes to trigger reactivity
- Thinking assignment causes error
const state = shallowRef({ count: 0, nested: { value: 1 } });
state.value.nested.value = 5;
console.log(state.value.nested.value);Solution
Step 1: Analyze shallowRef behavior
shallowReftracks only changes to the reference itself, not nested properties inside the object.Step 2: Understand nested mutation effect
Changingstate.value.nested.valueupdates the nested property but does not trigger Vue reactivity updates.Final Answer:
Nested property change won't trigger reactivity -> Option AQuick Check:
shallowRef ignores nested property changes [OK]
- Expecting nested changes to trigger updates
- Confusing shallowRef with reactive
- Thinking this causes syntax or runtime errors
const state = shallowReactive({ user: { name: 'Alice', age: 30 } });
watch(() => state.user, (newVal, oldVal) => {
console.log('User changed:', newVal);
});
state.user.name = 'Bob';What is the expected behavior?
Solution
Step 1: Understand shallowReactive and watch
shallowReactivetracks only top-level properties reactively. The watch onstate.usertriggers only if theuserobject reference changes.Step 2: Analyze nested property mutation
Changingstate.user.namemutates a nested property but does not replace theuserobject, so the watch callback does not run.Final Answer:
The watch callback runs only ifstate.useris replaced entirely -> Option AQuick Check:
shallowReactive watches top-level refs only [OK]
- Expecting watch to detect nested property changes
- Assuming watch runs on every nested mutation
- Confusing shallowReactive with deep reactive
Ready to prove it?
Pass the test and this pattern moves unknown
