All quizzesMedium
watch & Composables — Series 2
Preview — 3 of 10 questions
Why does this watcher fire when user.address.city changes, but not when user.address.zip changes?
javascript
import { reactive, watch } from 'vue'
const user = reactive({
name: 'Ada',
address: { city: 'London', zip: 'E1 6AN' },
})
watch(
() => user.address.city,
(newCity, oldCity) => {
console.log(`City changed: ${oldCity} → ${newCity}`)
}
)AIt doesn't actually work — watch can't take a function as its source, only a ref or reactive object directly
BPassing a getter function as the source tells watch to track only the reactive dependencies read inside that function — here, only user.address.city is read, so only changes to that specific field trigger the callback; zip was never read by the getter, so it's simply not tracked
CThe getter function form watches the entire user object deeply — both city and zip changes should trigger it, this is a bug in the example
DGetter-function sources only work with refs, not properties nested inside a reactive() object
Given this setup, how many times does "Calculating..." get logged?
javascript
import { ref, computed } from 'vue'
const a = ref(1)
const b = ref(2)
const sum = computed(() => {
console.log('Calculating...')
return a.value + b.value
})
console.log(sum.value) // read #1
console.log(sum.value) // read #2 — same read, no change
a.value = 10
console.log(sum.value) // read #3 — a changedAFour times — once per console.log(sum.value) call, plus once for the a.value = 10 assignment itself
BOnce — computed only ever evaluates its getter a single time, no matter how many times a dependency changes afterward
CTwice — once for the very first read (read #1), and once again after a.value = 10 changes a tracked dependency; read #2 reuses the cached result from read #1 since nothing changed between them
DThree times — once per console.log(sum.value) call, since reading .value always re-runs the getter
What's different about how this component reacts to state changes, compared to using reactive()?
javascript
import { shallowReactive } from 'vue'
const state = shallowReactive({
user: { name: 'Ada', preferences: { theme: 'dark' } },
loginCount: 0,
})
function renameUser() {
state.user.name = 'Grace' // (1) mutating a nested property
}
function incrementLogin() {
state.loginCount++ // (2) mutating a top-level primitive
}
function replaceUser() {
state.user = { name: 'New', preferences: { theme: 'light' } } // (3) replacing the whole nested object
}AshallowReactive() behaves identically to reactive() in every case — the "shallow" only affects refs inside the object, not plain nested objects
BNone of (1), (2), or (3) are reactive with shallowReactive() — only reactive() supports any of these mutations
CshallowReactive() makes every property reactive except functions — behaves the same as reactive() for all data properties
DOnly top-level properties are made reactive — mutating state.loginCount (2, a top-level primitive) triggers updates, and replacing state.user entirely (3, a top-level property reassignment) also triggers updates, but mutating a property nested inside state.user (1) does not, since state.user itself isn't converted into a reactive proxy
Sign up free to play
Answer all 10 questions (7 more), see explanations for every answer, and track your score.