Computed and Watch

Introduction

Computed properties derive values from reactive state with caching—ideal for formatted text and filtered lists. Watchers run side effects when data changes—API calls, logging, syncing to localStorage. This chapter covers computed, watch, and watchEffect, and when to prefer each over template expressions or methods.

Prerequisites

computed Basics

Code explanation:

  • computed returns a readonly ref by default
  • Re-runs only when firstName or lastName change
  • Template unwraps fullName like a ref

computed vs Methods vs Template Logic

ApproachCaches resultUse
Template expressionNoTrivial math
MethodNo (runs each render)Event handlers
computedYesDerived lists, labels, flags

Writable computed

Rare but useful—split get/set:

watch

Explicit source + side effect:

Watch options:

OptionMeaning
immediate: trueRun callback once on setup
deep: trueDeep watch reactive object
flush: 'post'After DOM update

Watch multiple sources:

typescript
watch([firstName, lastName], ([first, last]) => {
  console.log(first, last);
});

Watch a getter:

typescript
watch(
  () => state.user.id,
  (id) => { /* ... */ }
);

watchEffect

Auto-tracks dependencies used inside:

vue
<script setup lang="ts">
import { ref, watchEffect } from "vue";
 
const count = ref(0);
 
watchEffect(() => {
  document.title = `Count: ${count.value}`;
});
</script>

Cleanup on re-run or unmount:

typescript
watchEffect((onCleanup) => {
  const timer = setInterval(() => {}, 1000);
  onCleanup(() => clearInterval(timer));
});
watchwatchEffect
SourceExplicitAutomatic
Old valueAvailableNo
LazyDefault lazyRuns immediately

Use watch when you need old/new values or precise control; watchEffect for quick side effects.

When Not to Watch

Prefer computed for derived data—not watch copying state:

typescript
// Avoid
watch(a, (v) => { b.value = v * 2 });
 
// Prefer
const b = computed(() => a.value * 2);

Use watch for async side effects (fetch, timers, localStorage).

localStorage Sync Example

Pinia persistence plugins scale this pattern—Pinia.

Practice Exercise

Add to todo filter example:

  1. activeCount computed — number of undone todos
  2. watch on filter — console.log filter changes (dev only)
  3. Replace template visibleTodos() method with filteredTodos computed

FAQ

computed vs watch for filtered list?

computed—pure derivation, cached.

watch immediate vs watchEffect?

Both run on start; watch needs immediate: true.

Deep watch performance?

Expensive on large objects—watch specific fields or use immutable updates.

Async in computed?

No—computed must be synchronous. Use watch + ref for async results.

Same as React useMemo/useEffect?

Rough analogy—computed ≈ memoized derive; watch ≈ effect on dependency.

Stop watch?

typescript
const stop = watch(source, callback);
stop();

Useful in composables cleaned up on unmount.