深入理解 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) // 这不是响应式变量
})

解决方法:使用 ref 或 reactive


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

相关推荐
静默回滚6 分钟前
iPhone照片电脑上打不开:HEIC解码从原理到WASM
前端
dsyyyyy110115 分钟前
Vue 3 Watch 监视完全指南
前端·javascript·vue.js
航飞光电市场经理30 分钟前
人员定位系统“全栈自研”技术解析:从射频前端到定位引擎的架构拆解
前端·架构
Apifox33 分钟前
Apifox 9 月更新|CLI 能力升级、GitLab 私有化部署接入与产品体验优化
前端·后端·测试
deli00734 分钟前
随机乱跳为什么能画出完美三角形:混沌游戏分形实验室
前端
Gizzap_Tech41 分钟前
国内官网增加英文版:URL、语言切换与 hreflang 怎么配置?
前端
剪刀石头布啊1 小时前
泛洪DFS、BFS
前端
qetfw1 小时前
Windows Server AD CS:根 CA、Web 证书模板与域内自动注册
前端·windows·windows-server
剪刀石头布啊1 小时前
为什么React组件很少前缀,而vue的不少组件都有前缀
前端
剪刀石头布啊1 小时前
gird网格布局
前端