深入理解 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 中最强大的响应式工具之一,但也最容易被误用。理解它的"立即执行"、"依赖追踪"和"清理机制",才能用好它!

相关推荐
你真的可爱呀3 小时前
uniapp+vue3项目中的常见报错情况以及解决方法
前端·vue.js·uni-app
差点GDP6 小时前
模拟请求测试 Fake Rest API Test
前端·网络·json
酒尘&7 小时前
Hook学习-上篇
前端·学习·react.js·前端框架·react
houyhea8 小时前
从香港竹脚手架到前端脚手架:那些"借来"的发展智慧与安全警示
前端
哈哈~haha8 小时前
Step 14: Custom CSS and Theme Colors 自定义CSS类
前端·css·ui5
Ndmzi8 小时前
Matlab编程技巧:自定义Simulink菜单(理解补充)
前端·javascript·python
我命由我123458 小时前
VSCode - VSCode 修改文件树缩进
前端·ide·vscode·前端框架·编辑器·html·js
SoaringHeart9 小时前
Flutter组件封装:验证码倒计时按钮 TimerButton
前端·flutter
San30.9 小时前
深入理解 JavaScript OOP:从一个「就地编辑组件」看清封装、状态与原型链
开发语言·前端·javascript·ecmascript
AAA阿giao9 小时前
JavaScript 原型与原型链:从零到精通的深度解析
前端·javascript·原型·原型模式·prototype·原型链