0


Vue3-Watch踩坑-watch监听无效

ref 与 reactive

ref函数和reactive函数都是用来定义响应式数据

但是reactive更适合定义引用类型、ref适合定义基本数据类型(可接收基本数据类型和对象)

reactive

1、 深层次响应式,本质是将传入的数据包装成一个Proxy对象
2、 参数必须是对象或者数组,如果要让对象的某个元素实现响应式时,需要使用toRefs,这样每个都需要采用value方式访问

ref

1、函数参数可以是基本数据类型,也可以接受对象类型
2、如果参数是对象类型时,其实底层的本质还是reactive
3、ref响应式原理是依赖于Object.defineProperty()的get()和set()的

watch

在自身组件监听 reactive 对象

let a =reactive({test:123,bg:456,hh:{hhh:78}})// 定时器 1setTimeout(()=>{
  a.test =456},2000)// 定时器 2setTimeout(()=>{
  a.hh.hhh =56},4000)// 定时器 3setTimeout(()=>{
  a ={}},6000)// watch(a,()=>{// 定时器1, 2 可以触发监听, 不需要deep也可以// 定时器3 不能触发监听, 因为对象的地址已经发生改变了
  console.log("change")})// 函数返回方式 采用deep可以监听, 不加deep不能监听 watch(()=> a,()=>{
    console.log(" func change")},{deep:true})

为什么不加 deep不能监听呢,直接从源码看

functionwatch(source, cb, options){if(!isFunction(cb)){warn2(`\`watch(fn, options?)\` signature has been moved to a separate API. Use \`watchEffect(fn, options?)\` instead. \`watch\` now only supports \`watch(source, cb, options?) signature.`);}returndoWatch(source, cb, options);}functiondoWatch(source, cb,{ immediate, deep, flush, onTrack, onTrigger }=EMPTY_OBJ){// 代码不完整,截取部分...if(isRef(source)){getter=()=> source.value;
      forceTrigger =isShallow(source);}elseif(isReactive(source)){// 这里 ,如果 source 是 reactive// 则 deep = true // 而 deep 为true 后面会 执行traversegetter=()=> source;
      deep =true;}elseif(isArray(source)){
      isMultiSource =true;
      forceTrigger = source.some((s)=>isReactive(s)||isShallow(s));getter=()=> source.map((s)=>{if(isRef(s)){return s.value;}elseif(isReactive(s)){returntraverse(s);}elseif(isFunction(s)){returncallWithErrorHandling(s, instance,2/* WATCH_GETTER */);}else{warnInvalidSource(s);}});}elseif(isFunction(source)){// 如果是函数,//最终 getter () => fn()// deep为false,因此不走 traverse()if(cb){getter=()=>callWithErrorHandling(source, instance,2/* WATCH_GETTER */);}else{getter=()=>{if(instance && instance.isUnmounted){return;}if(cleanup){cleanup();}returncallWithAsyncErrorHandling(
            source,
            instance,3/* WATCH_CALLBACK */,[onCleanup]);};}}else{
      getter =NOOP;warnInvalidSource(source);}....if(cb && deep){const baseGetter = getter;getter=()=>traverse(baseGetter());}}

traverse 深度遍历整个对象,深层次的访问其所有的响应式变量,并收集依赖

在自身组件监听 ref 对象

let a =ref({test:123,bg:456,hh:{hhh:78}})setTimeout(()=>{
  a.value.test =456},2000)setTimeout(()=>{
  a.value.hh.hhh =56},4000)setTimeout(()=>{
  a.value ={}},6000)// 注意下面两种写法 一个是 a , 一个是 a.value// 从源码可知, 如果是 a, 那么走isRef(source)分支, 如果是 a.value 那么走 isReactive(分支)// 这里不给出结果,动手试试watch(a.value,(val)=>{
  console.log(val,"change")})watch(a,(val)=>{
  console.log(val,"change")})// 如果是 函数返回的方式呢? 其实也分两种,类推即可,同时也需要注意是否需要加 deep 属性watch(()=> a.value,(val)=>{
  console.log(val,"change")})watch(()=> a,(val)=>{
  console.log(val,"change")})

如果在子组件需要监听父组件的数据,同时父组件可以通过v-model双向绑定时需要非常注意,不然可能出现一些bug

如果watch监听无效,根据你的数据结构分析是否是因为写法不正确导致。

文章来自我个人搭建的博客,https://cxid.gitee.io/

标签: 前端 vue.js

本文转载自: https://blog.csdn.net/qq_40441489/article/details/128004872
版权归原作者 qq_40441489 所有, 如有侵权,请联系我们删除。

“Vue3-Watch踩坑-watch监听无效”的评论:

还没有评论