The Problem

Setting immediate: true on a Vue watcher causes the callback to run immediately when the component mounts. This often leads to duplicate API calls, unnecessary side effects, or operations that should only happen in response to actual data changes.

Symptoms

  • API endpoint called twice on page load (once by setup, once by watch)
  • Analytics event fires on mount even though nothing changed
  • Form validation runs before user has interacted with anything
  • Database writes triggered on every component mount

Real Error Scenario

```javascript // Component mounts, fetchData runs here onMounted(() => { fetchData(); });

// AND it runs again here because immediate: true watch(searchQuery, (newVal) => { fetchData(newVal); }, { immediate: true }); ```

The API gets hit twice: once from onMounted and once from the watch's immediate trigger.

How to Fix It

Fix 1: Remove onMounted, Let Watch Handle Initial Load

```javascript // Only watch handles the initial load watch(searchQuery, (newVal) => { fetchData(newVal); }, { immediate: true });

// Remove the duplicate onMounted call ```

Fix 2: Use a Flag to Skip First Run

```javascript let isFirstRun = true;

watch(searchQuery, (newVal) => { if (isFirstRun) { isFirstRun = false; return; // Skip mount trigger } fetchData(newVal); }); ```

Fix 3: Use watchEffect with Conditional Logic

javascript
watchEffect((onCleanup) => {
  if (!searchQuery.value) return; // Skip if empty on mount
  fetchData(searchQuery.value);
});

Fix 4: Use a Dedicated Init Function

```javascript const initialized = ref(false);

watch(searchQuery, async (newVal) => { if (!initialized.value) { initialized.value = true; if (!newVal) return; // Skip initial empty value } await fetchData(newVal); }); ```

When immediate: true Is Actually Correct

javascript
// This IS correct: the watch IS the initial data fetch
watch(userId, async (id) => {
  if (!id) return;
  const user = await fetchUser(id);
  userData.value = user;
}, { immediate: true });

Use immediate: true when the watcher IS the data source and you want it to run on mount. Do NOT use it when you already have another mechanism (like onMounted) handling the initial load.