Interview answer drill

Use this Vue interview question to rehearse a quick answer, common mistake, follow-up, and production pitfall.

Computed vs watch in Vue: derived state (cached) vs side effects (imperative)Frontend interview answer

HighIntermediateVue
Interview focus

This Vue interview question tests whether you can explain the Difference Between computed and watch in Vue, connect it to production trade-offs, and handle common follow-up questions.

  • the Difference Between computed and watch in Vue explanation without falling back to memorized docs wording
  • Computed and Watchers reasoning, edge cases, and production failure modes
  • How you would answer the most likely Vue interview follow-up
Practice more Vue.js interview questions
Interview quick answer

Computed properties and watchers both react to reactive changes, but they solve different problems: computed is for derived state (cached, declarative), while watch is for side effects (async/imperative work triggered by changes).

Full interview answer

Core idea

Computed = a derived value (like a formula). Vue tracks its dependencies and caches the result until one of them changes.
Watch = run code when something changes. It’s meant for side effects (fetching, logging, syncing, timers), not for producing values for the template.

Aspect

computed

watch / watchEffect

Primary purpose

Derived state (calculate a value from other reactive state)

Side effects (do something when state changes)

Caching

Yes (cached until deps change)

No (runs when triggered)

Evaluation model

Lazy: recomputes when accessed after being invalidated

Eager: runs callback when source changes (timing configurable via flush)

Return value

Yes (you read it like a value)

No (callback-driven; produces effects, not a value)

Async work

Avoid (keep it pure)

Yes (common: API calls + cancellation)

Common mistake

Putting side effects in computed

Using watch to keep derived state in sync (duplicate state)

Computed is for values; watch is for effects.

Anti-pattern (common in interviews): using watch for derived state

This duplicates state and can drift out of sync. Prefer computed unless you truly need an effect.

HTML
<!-- BAD: derived state via watch (duplicate state) -->
<script setup>
import { ref, watch, computed } from 'vue';

const first = ref('Mina');
const last = ref('Yilmaz');

const fullNameViaWatch = ref('');
watch([first, last], ([f, l]) => {
  fullNameViaWatch.value = `${f} ${l}`;
}, { immediate: true });

// GOOD: derived state via computed (cached, always in sync)
const fullName = computed(() => `${first.value} ${last.value}`);
</script>

<template>
  <p>watch-derived: {{ fullNameViaWatch }}</p>
  <p>computed: {{ fullName }}</p>
</template>
                  

Watchers (the right use): side effects + async + cancellation

When a value changes and you need to do something (fetch, analytics, sync URL, write to storage), use watch. Use cleanup to avoid race conditions (old request finishing after a new one).

HTML
<script setup>
import { ref, watch } from 'vue';

const query = ref('');
const results = ref([]);
const error = ref(null);

watch(query, async (q, _prev, onCleanup) => {
  if (!q.trim()) {
    results.value = [];
    error.value = null;
    return;
  }

  const ctrl = new AbortController();
  onCleanup(() => ctrl.abort());

  try {
    error.value = null;
    const res = await fetch(`/api/search?q=${encodeURIComponent(q)}`, { signal: ctrl.signal });
    results.value = await res.json();
  } catch (e) {
    // Ignore abort; handle real errors
    if (e?.name !== 'AbortError') error.value = e;
  }
}, { flush: 'post' });
</script>

<template>
  <input v-model="query" placeholder="Search..." />
  <pre v-if="error">{{ error }}</pre>
  <ul>
    <li v-for="r in results" :key="r.id">{{ r.title }}</li>
  </ul>
</template>
                  

Key options you should know (interview-level)


  • immediate: true runs the watcher once on setup (useful for initial fetch).

  • deep: true watches nested mutations (use sparingly; can be expensive). Prefer watching a specific getter like () => obj.a.b.

  • flush: 'pre' (default), 'post' (after DOM updates), 'sync' (runs immediately; use carefully).

  • watchEffect(): tracks dependencies automatically (great for effects that depend on many reactive reads), but use it only for effects (same rule: not for derived display values).

Rule of thumb

If the result is a value you want to render (filtering, formatting, totals) → computed.
If you need to do something when it changes (fetch, sync, log, imperative updates) → watch.

Similar questions
Guides
Preparing for interviews?

Use this as one explanation rep, then continue with the Vue.js interview questions cluster or a guided prep path.