欢迎光临仙桃市分类吧
详情描述

watchEffect 是 Vue3 响应式系统的核心 API 之一,它自动追踪依赖并在依赖变化时重新执行回调函数。下面从核心用法和原理两个维度进行解析:

一、核心用法

1. 基本使用

import { watchEffect, ref } from 'vue'

const count = ref(0)

// 自动追踪依赖,当 count 变化时重新执行
watchEffect(() => {
  console.log(`count is: ${count.value}`)
})

2. 清理副作用

watchEffect((onCleanup) => {
  const timer = setInterval(() => {
    console.log('tick')
  }, 1000)

  // 清理函数:在下一次执行前或停止监听时调用
  onCleanup(() => clearInterval(timer))
})

3. 配置选项

watchEffect(
  () => { /* ... */ },
  {
    flush: 'post',     // 'pre' | 'post' | 'sync'
    onTrack(e) {       // 调试:追踪依赖时触发
      debugger
    },
    onTrigger(e) {     // 调试:依赖变化触发重新执行时
      debugger
    }
  }
)

4. 停止监听

const stop = watchEffect(() => { /* ... */ })

// 手动停止
stop()

二、原理解析

1. 依赖自动追踪机制

// 简化版原理示意
function watchEffect(effect) {
  let cleanup

  const reactiveEffect = new ReactiveEffect(() => {
    // 执行清理函数
    if (cleanup) cleanup()

    // 开启依赖收集
    effectTrackDepth++
    activeEffect = reactiveEffect

    // 执行用户回调,自动收集依赖
    const result = effect(onCleanup => {
      cleanup = onCleanup
    })

    // 结束收集
    effectTrackDepth--
    activeEffect = undefined

    return result
  })

  reactiveEffect.run()
  return () => reactiveEffect.stop()
}

2. 响应式系统交互

执行流程:
1. 创建 ReactiveEffect 实例
2. 执行 effect.run() 
3. → 触发 track() 开始依赖收集
4. → 执行用户回调,访问响应式数据
5. → 响应式数据的 getter 触发,将当前 effect 添加到依赖集合
6. → 回调执行完毕,结束收集
7. → 响应式数据变化时触发 trigger()
8. → 找到对应的 effect 并重新执行

3. flush 时机控制

  • pre(默认):组件更新前执行
  • post:组件更新后执行,可访问到 DOM
  • sync:同步执行,响应式数据变化后立即执行

三、与 watch 的区别

特性 watchEffect watch
依赖收集 自动 显式指定
初始执行 立即执行 可配置
访问新旧值 不支持 支持
使用场景 副作用聚合 特定响应式源变化

四、最佳实践

1. 适用场景

// 场景1:自动依赖多个数据
watchEffect(() => {
  fetchData(query.value, filter.value)
})

// 场景2:DOM 操作(使用 flush: 'post')
watchEffect(() => {
  if (isOpen.value) {
    nextTick(() => inputRef.value?.focus())
  }
}, { flush: 'post' })

2. 注意事项

// ❌ 避免异步回调中的依赖追踪
watchEffect(async () => {
  // await 之后的响应式访问不会被追踪!
  const data = await fetch(url)
  console.log(someRef.value) // 不会被追踪
})

// ✅ 正确的异步用法
watchEffect(() => {
  const id = userId.value // 同步收集依赖
  fetchUser(id).then(user => {
    // 这里可以访问,但不会建立响应式关联
  })
})

3. 性能优化

// 使用响应式对象而非多个 ref
const filters = reactive({
  keyword: '',
  status: 'active',
  page: 1
})

// 单个 watchEffect 替代多个 watch
watchEffect(() => {
  search(filters.keyword, filters.status, filters.page)
})

五、源码关键设计

EffectScope:管理 effect 的生命周期,组件卸载时自动清理 ReactiveEffect:封装副作用函数,提供调度和停止能力 全局依赖栈:处理嵌套 effect 的依赖收集 调度器(scheduler):控制 effect 的执行时机和顺序

watchEffect 体现了 Vue3 响应式系统的设计哲学:自动追踪 + 显式控制,既提供了便利性,又通过 API 设计避免了过度“魔法”。

相关帖子
公积金贷款利率与住房公积金余额,余额越多息越少
公积金贷款利率与住房公积金余额,余额越多息越少
传统除湿剂、除湿盒与现代除湿机,在应对回南天时各自的优劣势是什么?
传统除湿剂、除湿盒与现代除湿机,在应对回南天时各自的优劣势是什么?
理发店在正月期间的营业情况是否会受到这一习俗的影响?
理发店在正月期间的营业情况是否会受到这一习俗的影响?
仙桃市ISO22000食品安全管理体系认证|企业注册代办公司,专业代办服务
仙桃市ISO22000食品安全管理体系认证|企业注册代办公司,专业代办服务
不同汽车品牌的发动机技术,在应对严格排放标准时主要采取了哪些不同路径?
不同汽车品牌的发动机技术,在应对严格排放标准时主要采取了哪些不同路径?
平顶山市注销公司-装修公司注册,本地代办公司
平顶山市注销公司-装修公司注册,本地代办公司
蚌埠市品牌网站定制开发|网站维护,一站式建站服务
蚌埠市品牌网站定制开发|网站维护,一站式建站服务
保山市公司地址变更办理|注册公司价格,24小时在线
保山市公司地址变更办理|注册公司价格,24小时在线
抵押过桥垫资费用是多少?抵押垫资费用构成与收费标准解析
抵押过桥垫资费用是多少?抵押垫资费用构成与收费标准解析
大连市房产网站建设#网站开发设计,收费标准
大连市房产网站建设#网站开发设计,收费标准
玉林市120长途救护车电话是多少,长途120急救车租赁,按公里收费
玉林市120长途救护车电话是多少,长途120急救车租赁,按公里收费
益阳市一条龙殡葬服务办理-丧葬服务车租赁,白事出殡服务
益阳市一条龙殡葬服务办理-丧葬服务车租赁,白事出殡服务
北京公积金贷款办理费用,首都贷款成本全解析
北京公积金贷款办理费用,首都贷款成本全解析
房抵贷申请流程:线下网点提交资料、银行审批、评估公司上门、抵押登记、放款到账
房抵贷申请流程:线下网点提交资料、银行审批、评估公司上门、抵押登记、放款到账
东营市公司注销代办服务|企业注册代办,欢迎电话咨询
东营市公司注销代办服务|企业注册代办,欢迎电话咨询
家属能否凭借关系证明,代为查询或复印患者的病历资料?
家属能否凭借关系证明,代为查询或复印患者的病历资料?
沧州市公司减资费用-营业执照注册代办,全程代办,不成功不收费
沧州市公司减资费用-营业执照注册代办,全程代办,不成功不收费
沧州市网站改版#网站优化推广服务,专业团队
沧州市网站改版#网站优化推广服务,专业团队
宁德市120长途救护车司机电话,病人护送救护车租赁,就近派车
宁德市120长途救护车司机电话,病人护送救护车租赁,就近派车
邢台市专业网站建设优化|定制化网站建设,专业设计团队
邢台市专业网站建设优化|定制化网站建设,专业设计团队