Vue3 中 computed、watch、watchEffect 的区别?

computed(计算属性)

基于其他响应式数据派生新值,有缓存,只有依赖变化时才重新计算。

const count = ref(0)
const double = computed(() => count.value * 2)
// 只有 count 变化时 double 才重新计算
// 多次访问 double 只计算一次(缓存)

// 可写 computed
const fullName = computed({
  get: () => `${first.value} ${last.value}`,
  set: (val) => {
    [first.value, last.value] = val.split(' ')
  }
})

watch(侦听器)

监听响应式数据变化,执行副作用。需要明确指定监听目标,有旧值和新值。

// 监听 ref
watch(count, (newVal, oldVal) => {
  console.log(`count: ${oldVal} → ${newVal}`)
})

// 监听 reactive 属性(需要 getter 函数)
watch(() => state.count, (newVal, oldVal) => {
  console.log(newVal)
})

// 监听多个
watch([count, () => state.name], ([newCount, newName]) => {
  console.log(newCount, newName)
})

// 配置选项
watch(count, callback, {
  immediate: true,  // 立即执行一次
  deep: true,       // 深度监听
  flush: 'post'     // DOM 更新后执行
})

watchEffect(立即执行侦听器)

自动收集依赖,不需要指定监听目标。立即执行一次,然后依赖变化时重新执行。

// 自动追踪 count 和 name
watchEffect(() => {
  console.log(count.value, name.value)
})

// 清理副作用
watchEffect((onCleanup) => {
  const timer = setInterval(() => {
    console.log(count.value)
  }, 1000)
  onCleanup(() => clearInterval(timer))
})

对比

特性 computed watch watchEffect
返回值 ✅ 返回新值 ❌ ❌
缓存 ✅ ❌ ❌
立即执行 ❌ 默认❌(可 immediate) ✅
指定监听 自动收集 ✅ 手动指定 自动收集
获取旧值 ❌ ✅ ❌
适合 派生数据 需要旧值的副作用 简单副作用

使用场景

// computed:派生数据
const filteredList = computed(() => 
  list.value.filter(item => item.includes(keyword.value))
)

// watch:需要旧值或精确控制
watch(selectedId, (newId, oldId) => {
  if (newId !== oldId) fetchData(newId)
}, { immediate: true })

// watchEffect:简单副作用
watchEffect(() => {
  document.title = `${count.value} items`
})

性能注意

同分类其他题目