Vue3中watch监听的五种写法

449 阅读3分钟

前言

以下文章是我个人学习的输出方式,目的是为了夯实自己的技术基础。

watch()

介绍

watch() 用于侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。

特点

watch() 默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数,只能侦听以下四种数据:

  • ref 定义的数据;
  • reactive 定义的数据;
  • 一个函数,返回一个值(getter函数);
  • ...或是由以上类型的值组成的数组;

示例一

监视 ref 定义的【基本类型】数据:直接写数据名即可,监视的是其 value 值的改变。

const count = ref(0)
watch(count, (count, prevCount) => {
  /* ... */
})

示例二

监视 ref 定义的【对象类型】数据:直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要手动开启深度监视。注意点如下:

  1. 若修改 ref 定义的对象中的属性,newValue 和 oldValue 都是新值,因为它们是同一个对象;
  2. 若修改整个 ref 定义的对象,newValue 是新值,oldValue 是旧值,因为不是同一个对象了;
<template>
   <div class="person">
       <h1>情况二:监视【ref】定义的【对象类型】数据</h1>
       <h2>姓名:{{ person.name }}</h2>
       <h2>年龄:{{ person.age }}</h2>
       <button @click="changeName">修改名字</button>
       <button @click="changeAge">修改年龄</button>
       <button @click="changePerson">修改整个人</button>
   </div>
</template>

<script lang="ts" setup name="Person">
import { ref, watch } from 'vue'

// 数据
let person = ref({
   name: '张三',
   age: 18
})

// 方法
function changeName() {
   person.value.name += '~'
}

function changeAge() {
   person.value.age += 1
}

function changePerson() {
   person.value = { name: '李四', age: 90 }
}

// 这种写法,调用 changePerson 会触发,newValue 和 oldValue 是不一样的
// 而调用 changeName 和 changeAge 是不会触发的,需要开启深度监听才行
watch(person, (newValue, oldValue) => {
   console.log('person变化了1', newValue, oldValue)
})

// 这种写法,点击按钮都会触发,
// 不同的是,调用 changeName 和 changeAge 触发的 newValue 和 oldValue 是一样的
watch(person, (newValue, oldValue) => {
   console.log('person变化了2', newValue, oldValue)
}, { deep: true })

</script>

示例三

监视 reactive 定义的【对象类型】数据,且默认开启了深度监视。

const state = reactive({ count: 0 })
watch(state, () => {
  /* 深层级变更状态所触发的回调 */
})

示例四

监视 refreactive 定义的【对象类型】数据中的【某个属性】,注意点如下:

  1. 若该属性值不是【对象类型】,需要写成函数形式。
  2. 若该属性值依然是【对象类型】,可直接编,也可写成函数,建议写成函数。

结论:监视的要是对象里的属性,那么最好写函数式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视。

const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount) => {
    /* ... */
  }
)

示例五

监视上述的多个数据

watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
  /* ... */
})

watchEffect()

介绍

立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。

watch() 对比 watchEffect()

  1. 都能监听响应式数据的变化,不同的是监听数据变化的方式不同;
  2. watch():要明确指出监视的数据;
  3. watchEffect():不用明确指出监视的数据(函数中用到哪些属性,那就监视哪些属性);

示例

const count = ref(0)

watch(count, (count, prevCount) => {
  /* ... */
})

watchEffect(() => console.log(count.value))
// -> 输出 0

count.value++
// -> 输出 1