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端全流程系统。

相关推荐
局外人LZ2 小时前
Decimal.js 完全指南:解决前端数值精度痛点的核心方案
开发语言·前端·javascript
飘若随风2 小时前
JS学习系列-01-什么是JS
开发语言·javascript·学习
摘星编程2 小时前
OpenHarmony环境下React Native:hitSlop热区扩展配置
javascript·react native·react.js
郑州光合科技余经理2 小时前
同城配送调度系统实战:JAVA微服务
java·开发语言·前端·后端·微服务·中间件·php
css趣多多3 小时前
动态路由,路由重置,常量路由,$ref,表单验证流程
开发语言·javascript·ecmascript
一只小bit3 小时前
Qt 绘图核心教程:从基础绘制到图像操作全解析
前端·c++·qt·gui
浪潮IT馆3 小时前
在 VSCode 中调试 JavaScript 的 Jest 测试用例
javascript·ide·vscode
乾元3 小时前
绕过艺术:使用 GANs 对抗 Web 防火墙(WAF)
前端·网络·人工智能·深度学习·安全·架构
HWL56793 小时前
一个CSS属性will-change: transform
前端·css