深入理解 Vue 3 中的 watchEffect

深入理解 Vue 3 中的 watchEffect:执行时机、陷阱与性能优化

一、watchEffect 是什么?

在 Vue 3 中,watchEffect 是组合式 API 中用于自动收集依赖并响应变化的副作用函数 。它在响应式依赖变动时重新运行,类似于 computed 的"副作用版"。

相比传统的 watch,它更自动、代码更简洁。


二、基本用法回顾

javascript 复制代码
import { ref, watchEffect } from 'vue'
​
const count = ref(0)
​
watchEffect(() => {
  console.log('count is:', count.value)
})

这段代码会:

  • 立即执行一次
  • 依赖收集 count
  • 当 count 变化时自动重新运行

三、关键难点:执行时机 & 执行机制

执行时机:

默认情况下,watchEffect 是在组件渲染前同步执行,但也可以通过选项控制:

arduino 复制代码
watchEffect(() => {
  console.log('DOM 渲染前执行')
}, {
  flush: 'pre' // 默认值
})

其他选项:

flush 类型 执行时机 使用场景
'pre' 渲染前(默认) 需要在 DOM 更新前读取状态
'post' 渲染后(DOM 更新后) 依赖 DOM 或使用 $el
'sync' 立即同步执行 依赖顺序执行或数据推送场景
scss 复制代码
watchEffect(() => {
  console.log(el.value?.offsetHeight)
}, {
  flush: 'post'
})

四、常见陷阱

1. 非响应式变量不会触发重新执行

javascript 复制代码
let name = 'Tom'
​
watchEffect(() => {
  console.log(name) // 这不是响应式变量
})

解决方法:使用 refreactive


2. 非主动使用 .value 的响应式变量不会被追踪

scss 复制代码
const user = ref({ name: 'Tom' })
​
watchEffect(() => {
  console.log(user.value) // 会触发
  // console.log(user.value.name) // 也会触发
  // 但如果只访问 user 而不访问 .value,无法追踪
})

3. 副作用函数里有异步操作要清理

javascript 复制代码
watchEffect((onCleanup) => {
  const timer = setInterval(() => {
    console.log('轮询')
  }, 1000)
​
  onCleanup(() => {
    clearInterval(timer)
  })
})

如果不清理副作用,组件卸载或数据切换时可能导致内存泄漏或逻辑冲突


五、性能优化建议

1.避免在 watchEffect 内执行复杂逻辑

scss 复制代码
watchEffect(() => {
  // 慎用:大量计算、循环、DOM 查询
  for (let i = 0; i < 10000; i++) { ... }
})

拆分逻辑改用 watch + debounce 更合适


2. 需要精确控制依赖时,优先使用 watch

javascript 复制代码
watch(() => someReactive.value, (newVal) => {
  // 更精细的控制
})

六、实践 Demo:表单自动保存

xml 复制代码
<script setup>
import { ref, watchEffect } from 'vue'

const form = ref({ title: '', content: '' })

watchEffect(() => {
  if (form.value.title || form.value.content) {
    localStorage.setItem('draft', JSON.stringify(form.value))
  }
})
</script>

<template>
  <input v-model="form.title" placeholder="标题" />
  <textarea v-model="form.content" placeholder="内容" />
</template>

自动保存草稿,用户刷新不会丢失。


七、总结:何时使用 watchEffect

使用时机 推荐工具
自动依赖追踪、副作用立即执行 watchEffect
精确监听某个属性并节流或控制频率 watch
不需要副作用,只计算依赖结果 computed

八、源码解析拓展(进阶)

在 Vue 3 中,watchEffect 实际通过 effect() 实现响应式副作用收集,并通过 scheduler 控制重新执行时机。

源码文件位置:packages/reactivity/src/effect.ts

核心关键代码(简化版):

javascript 复制代码
function watchEffect(fn, options) {
  const runner = effect(fn, {
    scheduler: queueJob, // 控制刷新节奏
    ...options
  })
}

总结:

watchEffect 是 Composition API 中最强大的响应式工具之一,但也最容易被误用。理解它的"立即执行"、"依赖追踪"和"清理机制",才能用好它!

相关推荐
伍哥的传说9 分钟前
CSS+JavaScript 禁用浏览器复制功能的几种方法
前端·javascript·css·vue.js·vue·css3·禁用浏览器复制
lichenyang45315 分钟前
Axios封装以及添加拦截器
前端·javascript·react.js·typescript
Trust yourself24330 分钟前
想把一个easyui的表格<th>改成下拉怎么做
前端·深度学习·easyui
三口吃掉你35 分钟前
Web服务器(Tomcat、项目部署)
服务器·前端·tomcat
Trust yourself24337 分钟前
在easyui中如何设置自带的弹窗,有输入框
前端·javascript·easyui
烛阴41 分钟前
Tile Pattern
前端·webgl
前端工作日常1 小时前
前端基建的幸存者偏差
前端·vue.js·前端框架
Electrolux1 小时前
你敢信,不会点算法没准你赛尔号都玩不明白
前端·后端·算法
a cool fish(无名)2 小时前
rust-参考与借用
java·前端·rust
只有干货3 小时前
前端传字符串 后端比较date类型字段
前端