请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

老师请问一下watch里面为什么要监听一个函数 () => props.data

不能直接监听 props.data 吗?为什么要把 props.data 变成一个函数的返回值来进行监听?

正在回答 回答被采纳积分+3

2回答

ustbhuangyi 2021-04-11 13:33:19

不可以喔,其实这个问题可以简化:

import { watch, reactive } from 'vue'

const a = reactive({
 b: []
})

watch(() => a.b, (newVal) => {
 console.log(newVal)
})

a.b = [1]

这样是可以执行回调函数的,但是改成这样就不行

watch(a.b, (newVal) => {
 console.log(newVal)
})

a.b = [1]

之所以不行,是因为你在 watch 的时候就已经访问了 a.b,这个时候它收集依赖对应的 effect 是 render effect。

而前面之所以可以,是因为 a.b 的访问延时了,watch 的 source 直接就是一个函数,然后当 a.b 真正访问的时候,这个时候收集依赖就是 watch 内部创建的 effect,这个 effect 对应的函数才会去执行回调函数 cb。

这块儿可以自己去看看 watch 实现的源码,也可以参考我在拉勾的 Vue.js 3.0 源码解析课程对这块的分析。

我再给你留一个问题,你好好思考一下。

watch(a.b, (newVal) => {
 console.log(newVal)
})

a.b.push(1) 

这样会不会执行回调,为什么。

3 回复 有任何疑惑可以回复我~
  • 目前我的理解是监听对象当中的属性(v2里面的深度监听), 
    在v3里面需要返回一个函数来监听, 监听普通的ref就可以直接写, 老师我这样理解对吗?
    回复 有任何疑惑可以回复我~ 2021-04-11 15:31:31
  • 嗯,差不多,最好是把这块实现的源码搞清楚,这样理解更深
    回复 有任何疑惑可以回复我~ 2021-04-11 18:10:44
  • 提问者 Elevens_regret #3
    这样会执行回调。
    去看了下老师写的源码解析,我理解的是 直接监听 a.b 的话,监听的是一个Reactive对象,在watch的内部,监听的如果是一个Reactive对象的话,会将deep属性设置为true,deep属性为true的情况下会执行traverse方法去递归访问对象深层的子属性,这次访问就会触发依赖收集,watcher创建的effect就会被收集。所以执行a.b.push(1),就能够触发这个effect,就执行了我们定义的cb。
    回复 有任何疑惑可以回复我~ 2021-04-11 19:46:40
ustbhuangyi 2021-04-11 23:50:31

https://img1.sycdn.imooc.com//szimg/60731a6d096ed7f816120528.jpg

在 traverse 的过程中,判断如果是数组,在遍历数组的过程中,访问了 value.length,这个时候触发了依赖收集,并且当前的 activeEffect 就是 watcher 内部创建的 effect。

2 回复 有任何疑惑可以回复我~
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信