watchEffect的两种错误用法

最近在看vue3官方文档watchEffect部分时,发现了一个tip:watchEffect 仅会在其同步执行期间,才追踪依赖。在使用异步回调时,只有在第一个 await 正常工作前访问到的属性才会被追踪。对于这句话不是很理解,自己先用写了个小例子试了一下,发现果然如此:修改count的值时,触发了副作用,但是修改msg时没有触发副作用执行。

javascript 复制代码
import { ref, watchEffect } from 'vue'
const count = ref(0)
const msg = ref('hello')
watchEffect(async () => {
console.log('count:', count.value)
await new Promise(resolve => setTimeout(resolve, 100))
console.log('msg:', msg.value)})
// 测试:修改 count 会触发副作用(同步阶段依赖)
count.value = 1 // 触发 watchEffect,打印 count:1 和 msg:hello

// 测试:修改 msg 不会触发副作用(异步阶段未被追踪)
msg.value = 'world' // 无反应

带着疑问,开始寻找答案!

首先要知道watchEffect收集依赖的原理:watchEffect的参数是一个函数 fn,watchEffect会把函数执行一次,并创建响应式 Effect,收集依赖。简化为下面的代码:

javascript 复制代码
let activeEffect = null
function watchEffect(fn) {
    activeEffect = fn
    fn()
    activeEffect = null
}

也就是说,在fn执行期间,activeEffect的值是 fn,fn 执行完毕后,activeEffect的值是null。activeEffect是 Vue3 响应式设计的关键,vue3在对象 get 执行时,收集依赖,在 set 执行时执行依赖。

javascript 复制代码
const effects = []
const count = {
    _value: 1,
    get value() {
        if(activeEffect) {
          effects.push(activeEffect)
        }
        return this._value
    }
    set value(val) {
        this._value = val
        effects.map((cb) => cb())
    }
}
  1. fn 函数在执行过程中,所有访问的响应式数据会触发 get 拦截器,get 函数里会对activeEffect是否有值做判断,此时,activeEffect的值正是 fn,于是就把 fn 放入依赖队列里,watchEffect的依赖收集完成。

  2. 但是当遇到 await 时,函数会 暂停执行,并将后续代码放入微任务队列。此时,当前 fn 的同步执行已结束,activeEffect 会被重置。

  3. await 后的代码恢复执行时,activeEffect 已不再指向当前 watchEffect 的 fn了,这也就解释了watchEffect 仅会在其同步执行期间,才追踪依赖。

了解原理以后,这是由 JavaScript 异步机制和 Vue3 响应式的 activeEffect 设计决定的。

然而还有一种情况也会出现watchEffect不执行副作用的情况:

javascript 复制代码
import { ref, watchEffect } from 'vue'
const count = ref(0)
let flag = false
watchEffect(() => {
    if(flag) {
      console.log('count的值改变了', count.value)
    }
})

setTimeOut(() => {
   flag = true
}, 1000)


setTimeOut(() => {
   count.vaue++
}, 2000)

2秒后,控制台并没有打印信息。这是为什么呢?

watchEffect在执行时,flag 是 false,因此并没有执行 console.log('count的值改变了', count.value) 这句代码,没有访问响应式数据count,count的 get 拦截器也不会触发,所以并没有收集依赖。即使后面修改count的值,也不会触发副作用函数执行。

如果在开发过程中,发现watchEffect的副作用函数没有执行时,就要检查一下是不是上述两种情况了!

团队介绍

智慧家技术平台-应用软件框架开发 」主要负责设计工具的研发,包括营销设计工具、家电VR设计和展示、水电暖通前置设计能力,研发并沉淀素材库,构建家居家装素材库,集成户型库、全品类产品库、设计方案库、生产工艺模型,打造基于户型和风格的AI设计能力,快速生成算量和报价;同时研发了门店设计师中心和项目中心,包括设计师管理能力和项目经理管理能力。实现了场景全生命周期管理,同时为水,空气,厨房等产业提供商机管理工具,从而实现了以场景贯穿的B端C端全流程系统。

相关推荐
QQ1__8115175152 小时前
Spring boot名城小区物业管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
钛态2 小时前
前端微前端架构:大项目的救命稻草还是自找麻烦?
前端·vue·react·web
一粒黑子2 小时前
【实战解析】阿里开源 PageAgent:纯前端 GUI Agent,一行JS让网页支持自然语言操控
前端·javascript·开源
独角鲸网络安全实验室2 小时前
2026微信小程序抓包全解析:从实操落地到合规风控,解锁前端调试新范式
前端·微信小程序·小程序·抓包·系统代理绕过·https证书严格校验·进程隔离
紫微AI2 小时前
前端文本测量成了卡死一切创新的最后瓶颈,pretext实现突破了
前端·人工智能·typescript
GISer_Jing2 小时前
AI前端(From豆包)
前端·aigc·ai编程
IT枫斗者2 小时前
前端部署后如何判断“页面是不是最新”?一套可落地的版本检测方案(适配 Vite/Vue/React/任意 SPA)
前端·javascript·vue.js·react.js·架构·bug
测试修炼手册2 小时前
[测试技术] 深入理解 JSON Web Token (JWT)
前端·json
AI老李2 小时前
2026 年 Web 前端开发的 8 个趋势!
前端
里欧跑得慢2 小时前
15. Web可访问性最佳实践:让每个用户都能平等访问
前端·css·flutter·web