Advanced Reactivity: shallowRef and triggerRef
shallowRef for performance, markRaw to exclude from reactivity, triggerRef for manual trigger.
Advanced Reactivity: shallowRef and triggerRef is a free Vue Academy lesson on CoddyKit. This is lesson 1 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Vue Academy learning path, and your progress syncs across the web and the CoddyKit app. The Vue Academy course includes 4 lessons in total.
Beyond ref and reactive
Vue’s deep reactivity is convenient but not always what you want. For large objects or external instances, deep tracking is wasteful. Vue offers shallowRef, triggerRef, and markRaw for fine control.
How ref Tracks Deeply
A normal ref holding an object makes the entire object deeply reactive — mutating any nested property triggers updates. Great for small state, costly for big structures.
import { ref } from "vue"
const user = ref({ name: "Ada", prefs: { theme: "dark" } })
user.value.prefs.theme = "light" // triggers update (deep)shallowRef: Only .value Is Reactive
shallowRef tracks reassignment of .value but does not track mutations inside the held value. Inner changes do not trigger renders.
import { shallowRef } from "vue"
const state = shallowRef({ count: 0 })
state.value.count++ // does NOT trigger update
state.value = { count: 1 } // DOES trigger (new .value)When to Use shallowRef
Use it for large immutable-ish data you replace wholesale, or to wrap external objects (a chart instance, a big dataset) where deep tracking adds overhead with no benefit.
const chart = shallowRef(null)
// chart.value = new Chart(...) replaces wholesaleThe Deep Mutation Problem
Sometimes you DO mutate inside a shallowRef (for performance) but still need a re-render at a controlled moment. Vue cannot see the change, so the UI goes stale.
const list = shallowRef([1, 2, 3])
list.value.push(4) // mutated, but no update firestriggerRef: Force an Update
triggerRef manually forces effects depending on a shallow ref to re-run, after you have mutated its contents. You batch many mutations, then trigger once.
import { shallowRef, triggerRef } from "vue"
const list = shallowRef([1, 2, 3])
list.value.push(4)
list.value.push(5)
triggerRef(list) // now the UI updatesA Performance Pattern
The pattern: hold a big structure in shallowRef, mutate it freely without per-change reactivity cost, then call triggerRef once when you want the view to reflect the batch.
function bulkUpdate(rows) {
for (const r of rows) data.value.push(r) // cheap
triggerRef(data) // one update
}markRaw: Opt Out Entirely
markRaw marks an object so Vue will never make it reactive, even inside a reactive or normal ref. Use it for third-party class instances that should not be proxied.
import { markRaw, reactive } from "vue"
const state = reactive({
map: markRaw(new ThirdPartyMap()),
})
// state.map is the raw instance, never a proxyWhy markRaw Matters
Wrapping complex class instances (maps, editors, websockets) in a reactive proxy can break their internal references or cause subtle bugs. markRaw keeps them untouched while still living inside reactive state.
Combining the Tools
These compose: a shallowRef holding a markRaw instance gives you a slot you can replace reactively, with an inner object Vue never proxies — ideal for external integrations.
const editor = shallowRef(null)
function init(el) {
editor.value = markRaw(new CodeEditor(el))
}Reactivity Cost vs Control
The trade-off: deep reactivity is effortless but heavier; shallow APIs give you control and performance at the cost of triggering updates yourself. Reach for them only when profiling shows a need.
Quick Check
Check your understanding of advanced reactivity.
Recap
You learned advanced reactivity controls:
shallowRefreacts only to.valuereassignment, not inner mutations — good for large or external data.triggerRefmanually forces updates after mutating a shallow ref’s contents (batch then trigger once).markRawpermanently opts an object out of reactivity, ideal for third-party class instances.- These give performance and control at the cost of triggering updates yourself.
Learn HTML with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 42
- Lessons
- 156
Frequently Asked Questions
Is the “Advanced Reactivity: shallowRef and triggerRef” lesson free?
Yes — any 3 lessons of the Vue Academy learning path, including “Advanced Reactivity: shallowRef and triggerRef”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Vue Academy course includes 4 lessons in total.
What will I learn in “Advanced Reactivity: shallowRef and triggerRef”?
shallowRef for performance, markRaw to exclude from reactivity, triggerRef for manual trigger. You practise Vue Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Vue Academy?
No prior experience is required. Vue Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 1 of 4.
How long does the “Advanced Reactivity: shallowRef and triggerRef” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Vue Academy lesson?
Yes. Every Vue Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Advanced Reactivity: shallowRef and triggerRef
- Composable Factories and Parameterized Composables
- State Machines with XState in Vue
- effectScope for Grouped Effects