Watchers
Shelf forgets everything on refresh. You want the books saved to the browser's storage every time the list changes, and a book's cover fetched whenever the selected book changes. Neither is a value to display, so computed is the wrong tool. These are side effects triggered by a change: the job of watch.
The rule
Computed returns a value; watch does something when a value changes.
watch takes a source and a callback. When the source changes, the callback runs with the new and old values:
import { ref, watch } from 'vue'
const selectedId = ref(1)
const cover = ref(null)
watch(selectedId, async (newId, oldId) => {
const res = await fetch(`/api/books/${newId}/cover`)
cover.value = await res.json()
})What can be a source:
- A ref:
watch(selectedId, ...). - A getter function:
watch(() => filters.genre, ...). You need this for a property of a reactive object.watch(filters.genre, ...)passes a plain string, which cannot be watched. - A reactive object:
watch(filters, ...)watches it deeply, every nested property. - An array of these, to react to any of several sources.
Options go in a third argument:
deep: truereacts to changes inside nested objects or arrays. Watching a ref that holds an array fires only when.valueis replaced; adddeepto catch apushor a flipped flag inside a book.immediate: trueruns the callback once right away, not just on the first change.
watch(books, (list) => {
localStorage.setItem('shelf', JSON.stringify(list))
}, { deep: true, immediate: true })watchEffect is the automatic version: you give it one function, it runs immediately, and it re-runs whenever any reactive value it read changes. No source to list, but also no old value.
watchEffect(() => {
document.title = `Shelf (${books.value.length})`
})The shortcut
Ask "Do I want a value, or an action?" A value to show → computed. An action such as saving, fetching, logging or touching something outside Vue → watch. Then ask "Is my source a ref, a getter or a reactive object?"
Value or action?
Writing to localStorage is an action. Use a watcher.
Drills
Answer fast — trust the rule.
Which job belongs in a watcher rather than a computed?
filters is reactive. How do you watch only filters.genre?
books is a ref holding an array. watch(books, save) does not fire when a book's read flag changes. What fixes it?
What does immediate: true add?
How does watchEffect differ from watch?
Remember
watch(source, callback, options)runs side effects when a source changes;watchEffecttracks automatically.- Shortcut: value → computed, action → watch; then name the source correctly.
- Trap: watching
obj.propdirectly instead of a getter, and forgettingdeepfor changes inside arrays.
