踩坑不断的watch

watch

今天看教程,发现vue3里面的watch坑超级多,特此记录下。

语法

vue3组件改为组合式组件,所需的配置大都需要自己去引入,watch也是如此。

watch(attr, callBack(newV, oldV), obj)

vue3将计算属性(computed),侦听属性(watch)等一些配置设计为了函数模式,使用的时候直接调用watch函数即可(前提是已经引入)。attr表示需要监听的数据,callBack则为需要处理的回调函数,参数同vue2一样,newV为改变后的数据,oldV为改变前的数据。obj为一个配置对象,可以配置vue2的deep,immediate属性。

不同使用情况不同分析

1.监听ref所定义一个响应式数据

let username = ref('fufu')
watch(username, (newV, oldV) => {
  console.log(newV, oldV);  //fufu~  fufu
})

修改给username 添加 ‘~’,触发侦听。值得庆幸的是这是vue3里面少有的没有坑的情况之一!

2.同时监听多个ref所定义一个响应式数据

在实际项目里,我们肯定会有监听多个数据的需求,在vue3里面,watch配置项已经可以多次使用,也就是说,想要监听多个数据,可以如下:

let username = ref('fufu')
let height = ref(170)
watch(username, (newV, oldV) => {
  console.log(newV, oldV);  //fufu~  fufu
})
watch(height , (newV, oldV) => {
  console.log(newV, oldV);  //171 170
})

但是这样写明显会造成大量的代码重复,vue3其实也支持在watch配置函数里面的第一个参数的位置放数组。

let username = ref('fufu')
let height = ref(170)
watch([username, height ], (newV, oldV) => {
  console.log(newV, oldV); 
})

当两个值都改变时,回调函数里面的新老值都会变成一个数组。
如fufu改成fufu~,170改成171的话,newV, oldV值为[‘fufu~’, 171], [‘fufu’, 170]

3.监听一个reactive所定义一个响应式数据(值为简单类型)

let person = reactive({
  age: 20,
  wages: 20
})
watch(person, (newV, oldV) => {
  console.log(newV, oldV);  
})

当我们将age加1的时候,打印出踩坑不断的watch
第一个坑出现了!!!我们惊奇的发现,它打印的oldV和newV竟然是一样的!!! 这并非我们代码的问题,是vue3本就存在的,无法解决。可能有人会想到既然reactive无法被监听,那我们使用ref定义对象不就行了?

let person = ref({
  age: 20,
  wages: 20
})
watch(person.value, (newV, oldV) => {
  console.log(newV, oldV);  
})

经过测试发现,其实结果是一样的。其实很好理解,ref方法定义一个对象时,也是去求助的reactive这个方法,说到底,定义对象用的都是reactive,并无区别。

还有人可能会提问说为什么这个时候监听需要.value,而之前不需要呢?这里就要提下watch监听的到底是什么?当监听一个ref定义的响应式对象时,不会开启自动深层次监听,而使用.vlaue就相当于是监听的reactive定义的响应对象,是会强制监听的。当然,我们也可以不写.value,而是在第三个参数里面配置下deep属性,同样可以实现。

并且坑远不止如此!!!
第二个坑出现了!!!

let demo = reactive({
  a: {
    b: {
      c: 10
    }
  }
})
watch(demo, (newV, oldV) => {
 console.log(newV, oldV, person)
})

当我们改变demo里面的c属性时,发现还是会变监听到。难道是默认开启深度监听?这里就不进行测试了,其实这就是一个坑,即使你在watch的第三个参数里面配置deep为false,他还是会被监听到。

那么我们永远拿不到正确的oldV值了嘛?
其实在日常开发中,oldV值我们用的是很少的,但是也不乏还是有需求需要,所以我们可以将需要监听的值转换为简单类型。

let age = ref(20)
let wages = ref(20)
watch(age , (newV, oldV) => {
  console.log(newV, oldV);  
})
watch(wages , (newV, oldV) => {
  console.log(newV, oldV);  
})

这是最笨的方法了,不推荐!!!
其实还有一种办法,那就是监听对象的属性,也就是情况四了

4.监听一个reactive所定义一个响应式数据的一个属性

let person = reactive({
  age: 20,
   wages: 20
 })
watch(() => person.age, (newV, oldV) => {
  console.log(newV, oldV);
 })

当我们改变数据时,发现newV, oldV值可以正确获取。

5.监听一个reactive所定义多个响应式数据

有情况二就一定也会出现情况4啦。

let person = reactive({
  age: 20,
  wages: 20
 })
watch([() => person.age, () => person.wages], (newV, oldV) => {
  console.log(newV, oldV);
 })

这里的newV, oldV值也会变成一个数组对应监听的几个值。

6.监听一个reactive所定义的一个响应数据(值为对象)

let demo = reactive({
  a: {
    b: {
      c: 10
    }
  }
})
watch(() => demo.a, (newV, oldV) => {
 console.log(newV, oldV, person)
})

然后我们改变数据c时惊奇的发现…为啥没有被监听?代码错了?并不是,仔细想想其实是我们忘记了deep属性。这个时候有人要反对啊,情况三你说的deep属性默认就有,并且还控制不了,只能为true,这里怎么就又需要手动添加呢?你问我我只能说第三个坑出现了!!!

上一篇:vue中watch的用法


下一篇:极客头条:字节跳动将推行1075工作制;iPhone和Apple Watch将支持车祸自动报警;马斯克推文发布曹植《七步诗》