0Pricing
Vue Academy · Lesson

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 — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Vue Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

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 wholesale

The 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 fires

triggerRef: 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 updates

A 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 proxy

Why 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:

  • shallowRef reacts only to .value reassignment, not inner mutations — good for large or external data.
  • triggerRef manually forces updates after mutating a shallow ref’s contents (batch then trigger once).
  • markRaw permanently opts an object out of reactivity, ideal for third-party class instances.
  • These give performance and control at the cost of triggering updates yourself.

Frequently asked questions

Is the “Advanced Reactivity: shallowRef and triggerRef” lesson free?

Yes — the full text of “Advanced Reactivity: shallowRef and triggerRef” is free to read here on the web, and the Vue Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Vue Academy course, upgrade to CoddyKit PRO.

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; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.

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

  1. Advanced Reactivity: shallowRef and triggerRef
  2. Composable Factories and Parameterized Composables
  3. State Machines with XState in Vue
  4. effectScope for Grouped Effects
← Back to Vue Academy