Using watch and computed in the Vue 3 Composition API

In the Vue 3 Composition API, computed and watch are two core tools for handling reactive data. Unlike the Options API, they are exposed as top-level functions in the Composition API, offering a clearer logical organization and greater flexibility. Understanding and mastering the differences between these two and their respective use cases is key to building high-performance, maintainable Vue applications.
computed is primarily used to derive new reactive values from existing reactive data. Its mechanism is quite unique: whenever its dependency source changes, computed automatically re-runs to update the result; if dependencies remain unchanged, it directly returns the cached result without recomputation. This "lazy calculation" characteristic makes computed an ideal choice for handling complex logical derivations, such as formatting dates, calculating totals, or generating dynamic text based on state.

When using computed, you simply pass a callback function as the argument; any reactive variables accessed within this function form a dependency relationship. Once these variables are modified in subsequent code, computed will automatically trigger an update. Here is a typical usage example:

import { ref, computed } from 'vue'

export default {
  setup() {
    const count = ref(0)
    
    // Define a computed property that depends on count
    const doubleCount = computed(() => count.value * 2)
    
    return {
      count,
      doubleCount
    }
  }
}

In this example, the value of doubleCount is always equal to twice the value of count. Regardless of how count changes, Vue will intelligently detect the dependency and update doubleCount without executing repeated multiplication operations until the dependencies change. This mechanism not only improves performance but also makes the code logic more intuitive and predictable.

Watch: Active Monitoring and Side Effect Handling

Unlike computed, watch does not directly return a calculated result; instead, it is used to monitor a reactive variable or function and execute specific side-effect operations when it changes. It is suitable for scenarios requiring external intervention, asynchronous requests, or complex conditional judgments, such as data loading, form validation, or third-party API calls.

watch supports various parameter configurations, including monitoring only object property changes, ignoring certain change types, and using the onCleanup hook within the callback to clean up resources. By flexibly configuring immediate (whether to execute immediately) and deep (whether to deeply monitor nested objects), developers can finely control monitoring behavior.

import { ref, watch } from 'vue'

export default {
  setup() {
    const user = ref({ name: 'Alice', age: 25 })
    
    // Monitor changes in user.name but do not deep monitor
    watch(user, (newVal, oldVal) => {
      console.log('User name changed:', newVal.name, 'Old value:', oldVal.name)
    }, { deep: false })
    
    // Monitor the entire object change and execute immediately
    watch(user, (newVal) => {
      console.log('User data updated:', newVal)
    }, { immediate: true })
    
    return { user }
  }
}

The above code demonstrates how watch adjusts monitoring granularity based on configuration options. When an object property changes individually, the callback function is triggered; if deep: true is not set, nested properties are not recursively checked. Additionally, through immediate: true, the callback can be executed immediately upon component initialization, which is suitable for scenarios requiring initial state processing.

Core Differences and Best Practice Selection

Although both computed and watch involve reactive data, their design philosophies are fundamentally different. computed represents a unidirectional, deterministic derivation process, suitable for generating static or semi-dynamic data views; whereas watch is bidirectional and may include side effects, making it more appropriate for handling asynchronous tasks or executing actions after state changes.

In actual development, the following principles should be followed when making a selection:

  • If the goal is to generate new reactive values for use in templates, prefer using computed and avoid directly modifying external state within callbacks.
  • If network requests, file operations, or other non-synchronous behaviors need to be triggered, watch must be used.
  • For frequently updated complex objects, consider using watchEffect instead of the traditional watch syntax to simplify code structure.

Furthermore, reasonably combining both can also improve development efficiency. For example, first use computed to calculate intermediate results, then use watch to monitor changes in these results and execute corresponding logic, thereby achieving a modular, high-cohesion code organization approach.

Mastering the essential differences and application scenarios of computed and watch will help you build both efficient and readable reactive application architectures in Vue 3 projects.