[最详细的Watch介绍]- Vue3中Watch的使用详情和注意事项

1,559 阅读8分钟

「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

Vue2.0的Watch想必大家已经很熟悉了,但是Vue3.0的Watch的用法,可能大家还不是特别熟练,所以我专门整理了一篇Vue3.0中关于Watch的几种用法,让在学习Vue3的小伙伴加以熟练!更加深入解和使用Watch!相信看完对你会有所帮助!

废话不多说,我们先来看Vue2.0中的最常见的用法

Vue2.0中的最常见的Watch用法:🐱‍👤

//数据
let sum = ref(0)
watch: {
    //简单监听
    sum(newValue,oldValue){
      console.log('sum的值变化了',newValue,oldValue)
    }
},

我定义了一个sum数值,在HTML 我写了一个点击事件,通过watch 我们就可以去监听到sum值得变化。这里得newWalue\color{#FF0000}{newWalue}为更新之后前得值,oldValue\color{#FF0000}{oldValue}为更新之后得值!

QQ图片20211120233215.png 这是一个最简单得监听,相信大家也都特别熟练,这里如果我们如果想在页面加载之后就进行一个即刻监听得话,我们可以给他在watch中增加两个值,也就是我们熟悉的

immediate: true,  // 立即监听

如果想深度监听的话,我们则需要添加

deep: true,  //  深度监听

以上就是Vue2.0中的监听用法,这里也不过多的去描述。

接下来我们来看一下

Vue3.0中Watch变化

首先,Watch在3.0中可以传递三个参数:

  • 参数一 数据源\color{#0000FF}{数据源}
  • 参数二 监听结果\color{#0000FF}{监听结果}
  • 参数三 配置项(如:深度监听、即刻监听)\color{#0000FF}{配置项(如:深度监听、即刻监听)}

我们先来看🐱‍🐉

情况一:

//情况一:监视ref所定义的一个响应式数据
/*  watch(sum, (newValue, oldValue) => {
   console.log('sum值变化了', newValue, oldValue)
 }, {immediate: true})*/

我们可以清楚的看到,三个参数我都配置上了,在配置项中,我开启了即刻监听。 我们来看一下控制台:

QQ图片20211120234211.png 效果显然易见,这就是在3.0中情况一的用法。 注意:这里监听的数据源是

//数据源
let sum = ref(0)

之所以提出来数据源,是因为后面会有所不同,让我们继续往下走✨

情况二:

//数据源
let sum = ref(0)
let msg = ref('你好啊,我是多个')

//情况二:监视ref所定义的多个个响应式数据
  watch([sum, msg], (newValue, oldValue) => {
    console.log('sum或msg变化了', newValue, oldValue)
  })

QQ图片20211120234618.png

从以上二种情况来看,其实变化并不是很大,而且我们上面监听的都是用ref定义的基本数据类型。


我们来看第三种情况,也就是会出现问题的情况三(最常用的一种情况!)。

情况三 是用来监视reactive所定义的一个响应式数据

情况三就比较有意思了,因为在情况三里,存在二个的问题🤦‍♂️:

  • 问题一: 你无法正确获取修改之前的值
  • 问题二: 强制开启了深度监听(无法关闭)

情况三:

// 源数据   reactive 
let person = reactive({
  name: "李雷",
  age: 18,
  obj: {
    height: "186",
    obj2: {
      ppp: 222
    }
  }
})
watch(person, (newValue, oldValue) => {
  console.log('person值变化了', newValue, oldValue)
})

QQ图片20211120235743.png

有兴趣的朋友可以去写一下,看看能不能关掉深度监听。

我尝试的是不能关闭!

不过,后面我会写出解决这二个问题的办法,还请您看完之后帮忙点一个小小赞~ 祝您生活愉快!涨薪!

看到这里你可能就会想了,如果我想监听某一个属性我们应该咋办哪? 情况四,来帮你解决疑问。


情况四:

let person = reactive({
  name: "李雷",
  age: 18,
  obj: {
    height: "186",
    obj2: {
      ppp: 222
    }
  }
})
//情况四:监视reactive所定义的一个响应式数据中的某一个属性
 watch(()=>person.age, (newValue, oldValue) => {
   console.log('person里面的age值变化了', newValue, oldValue)
 })

QQ图片20211121000711.png 没错,我们可以把第一个参数写成函数的形式,你想监听谁,你就把谁写成函数,函数有返回值,就是你监听的哪一个值!


情况五:

情况五也是类似的,只不过是监视的多个值

 //情况五:监视reactive所定义的一个响应式数据中的多个属性
/* watch([()=>person.age,()=>person.name], (newValue, oldValue) => {
   console.log('person值变化了', newValue, oldValue)
 })

QQ图片20211121001036.png


接下来我们来看二种特殊情况:

特殊情况一:

//对象reactive
let person = reactive({
  name: "李雷",
  age: 18,
  obj: {
    height: "186",
    obj2: {
      ppp: 222
    }
  }
})

//特殊情况  深度监视对象里面套对象的值 需要开启deep
/* watch([()=>person.obj], (newValue, oldValue) => {
   console.log('person值变化了', newValue, oldValue)
 },{deep:true})  
 //此处监听的是reactive定义对象中的某一个属性 所以得配置 deep*/

QQ图片20211121001913.png


特殊情况二 (当你想去监听ref的对象时):

当你去监听ref基本类型的时候,如果你在ref写的是对象类型,则ref会找到他的大哥帮助(reactive),也就是说 你在对象数据类型里面去使用ref做监听的话,他实际上还是调用的 reactive。

所以当你想监听的时候,需要写 personRef.value或者开启深度监听 deep:true

//ref
let personRef = ref({
  names: "韩梅梅",
  age: 20,
  obj: {
    height: "195",
    obj2: {
      ppp: 333
    }
  }
})
// 一个注意点 如果在 ref的基本类型值,写了.value  watch(msg.value, () => {} 
// 他会监听的是值的本身,所以这样并不可行
watch(personRef.value, (newValue, oldValue) => {
  console.log('person值变化了', oldValue, oldValue)
})

注意:在这里我们监测的数据源发生了变话,我们不在是监测的reactive数据源,而是ref!

详解:\color{#FF00FF}{详解:} 如果我们在这里不写personRef.value, 我们直接去写 personRef的话,我们监测的并不是对象里面的值,而是ref在解析的过程所生产的Reflmpl{...对象...} 这里所有生产的则是value:Proxy。而在Proxy里面才会有我们真正想监测的值! 使用personRef.value的话,我们是监测到的是Reflmpl所生产的 value --> Proxy。

QQ图片20211121003900.png

以上就是我们聊到的 5种情况、加2种特殊情况的用法😉


我们再来讨论一下,三个API

  • watchEffect() // 监听全局属性
  • shallowReactive() // 浅度监听
  • shallowRef() // 只处理基本的数据类型 不进行对象的处理

watchEffect() 监听全局属性

  • watch的套路:既要指明监视属性,也要指明监视的回调。

  • watchEffect的套路是:不用指明监视的那个属性,监视的回调函数中用到哪个属性,那就监视那个属性

  • watchEffect有点像computed:  (重点,面试可以聊)

    • 但computed的计算出来的值(回调函数的返回值),所以必须要写返回值
    • 而watchEffect更注重的过程(回调函数的函数体),所以不用写返回值
// watchEffect() 函数可以监听全局, 有个最大的特点就是 在函数里面你用到了谁
// 他就会监听谁,否则谁也不会监听,但是会认为开启立即监听。
  watchEffect(() => {
    const x1 = sum.value;
    console.log(x1)
    console.log('watchEffect执行了!')
  })

QQ图片20211121004355.png


shallowReactive() 浅度监听

// shallowReactive 只考虑第一层的响应式数据
/* let person = shallowReactive({
   name: "xuge",
   age: 18,
   obj: {
     aa: "文字",
     j1: {
       pop: 222
     }
   }
 })*/

shallowRef() 只处理基本的数据类型 不进行对象的处理

// shallowRef 值处理基本的数据类型 不进行对象的处理
// 这里如果换成 ref 是可以进行 响应式点击的,如果是shallowRef则不可以进行处理对象
let x = shallowRef({
  y: 0
})

注意: ref 会求助 reactive 所以 里面也是可以改变的所以是响应式, 但是shallowRef 不会求助任何属性 所以里面不会是响应式。


//深层次的去限制 响应式改变
// x1 = shallowReactive(person)

//浅层次的去限制 响应式改变
// x2 = readonly(x)

当然,这里还有很多细节,我并没有展开为话题进行叙述。

这里推荐几个值得你研究的问题:

  • watchEffect与 watch 有什么不同?(这里做了简便的回答,具体可以去官网查看对比!) 答:
- watch可以查看旧值, watchEffect不可以

- watch只有属性改变才执行, watchEffect初始执行一次,属性改变再执行

- watch要指定属性, watchEffect不需要

- watch不可以停止监听, watchEffect可以

- watch多次触发多次执行(不能节流), watchEffect可以
  • 基本类型 ref 和 shallowref 没有任何区别, 但是 如果是对象的话有区别ref 是可以进行 响应式点击的,shallowRef则不可以进行处理对象
  • shallowReactive 只处理最外层的响应式数据
  • shallowRef 只处理基本的数据类型 不进行对象的处理
  • shallowReactive,readonly 限制响应式 深和浅
  • toRaw 将reactive生产的响应式 转为普通的,让他变成不响应式的对象
  • markRaw 让一个属性 永远不会变成响应式的 后续,我也会一步一个脚印的去总结发文~ 您也可以点个关注~ 大家一起交流互相学习!

最后,我们来聊一下如何解决情况三的二个问题!

  • 问题一: 监听reactive数据 无法正确获取修改之前的值
  • 问题二: 监听reactive数据 强制开启了深度监听(无法关闭)

答: 3.0官方提供的有专门的api ,不用你手动关闭,reactive 本身就是每层都监听,你要是不想深度监听那就换shallowReactive,相应的ref 对应的也是有shallowReactive的,深度监听用reactive ,只想监听第一层,内部嵌套的对象懒得管那就加个shallow就行了,性能会更高,但是缺点是更新值麻烦,因为它就管第一层,其他懒得管。

以上就是我对Vue3.0中Watch中各种情况的了解,希望可以帮助在学习Vue3.0的朋友!🌹🌹🌹 如果有不对的地方,希望指正!我会非常感谢您的! 看完记得点个赞哦~ 谢谢!🤞🤞🤞