Files
agent-skills/skills/vue-best-practices/reference/watch-immediate-option.md
Jason Woltje f5792c40be feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories:
- anthropics/skills: 16 (docs, design, MCP, testing)
- obra/superpowers: 14 (TDD, debugging, agents, planning)
- coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth)
- better-auth/skills: 5 (auth patterns)
- vercel-labs/agent-skills: 5 (React, design, Vercel)
- antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo)
- Plus 13 individual skills from various repos

Mosaic Stack is not limited to coding — the Orchestrator and
subagents serve coding, business, design, marketing, writing,
logistics, analysis, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:27:42 -06:00

3.5 KiB

title, impact, impactDescription, type, tags
title impact impactDescription type tags
Use immediate Option Instead of Duplicate Initial Call LOW Duplicate code for initial call and watch callback reduces maintainability efficiency
vue3
watch
watchers
immediate
best-practices
DRY

Use immediate Option Instead of Duplicate Initial Call

Impact: LOW - Calling a function manually at setup and also in a watcher leads to duplicate code. The immediate: true option runs the watcher callback immediately with the current value, combining both behaviors.

Task Checklist

  • Use { immediate: true } instead of calling handler in onMounted/created
  • Consider watchEffect as an alternative (always runs immediately)
  • Remember immediate callback receives undefined as oldValue on first run

Incorrect:

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

const userId = ref(1)
const userData = ref(null)

// BAD: Duplicate calls - once in onMounted, once in watch
async function loadUser(id) {
  const response = await fetch(`/api/users/${id}`)
  userData.value = await response.json()
}

onMounted(() => {
  loadUser(userId.value)  // Initial call
})

watch(userId, (newId) => {
  loadUser(newId)  // On change
})
</script>
// Options API - BAD: Duplicate in created and watch
export default {
  data() {
    return { userId: 1, userData: null }
  },
  created() {
    this.loadUser()  // Initial call
  },
  watch: {
    userId() {
      this.loadUser()  // On change - duplicate!
    }
  },
  methods: {
    async loadUser() {
      const response = await fetch(`/api/users/${this.userId}`)
      this.userData = await response.json()
    }
  }
}

Correct:

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

const userId = ref(1)
const userData = ref(null)

// GOOD: Single watch with immediate runs on mount and on change
watch(
  userId,
  async (newId) => {
    const response = await fetch(`/api/users/${newId}`)
    userData.value = await response.json()
  },
  { immediate: true }
)
</script>
// Options API - GOOD: Using immediate option
export default {
  data() {
    return { userId: 1, userData: null }
  },
  watch: {
    userId: {
      async handler(newId) {
        const response = await fetch(`/api/users/${newId}`)
        this.userData = await response.json()
      },
      immediate: true
    }
  }
}

Alternative: watchEffect

<script setup>
import { ref, watchEffect } from 'vue'

const userId = ref(1)
const userData = ref(null)

// watchEffect always runs immediately - no option needed
watchEffect(async () => {
  const response = await fetch(`/api/users/${userId.value}`)
  userData.value = await response.json()
})
</script>

Handling oldValue on Initial Run

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

const count = ref(0)

watch(
  count,
  (newVal, oldVal) => {
    // On first run with immediate: true
    // oldVal is undefined
    if (oldVal === undefined) {
      console.log('Initial run, count is:', newVal)
    } else {
      console.log(`Count changed from ${oldVal} to ${newVal}`)
    }
  },
  { immediate: true }
)
</script>

One-Time Watch with once Option

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

const data = ref(null)

// Run only once when data becomes available
watch(
  data,
  (value) => {
    if (value) {
      initializeWithData(value)
      // Watcher automatically stops after this
    }
  },
  { once: true }
)
</script>

Reference