Vue 3响应式系统全解析:深入ref、reactive、computed、watch及watchEffect-四、watch

作用:监视数据的变化(和 Vue2 中的 watch 作用一致)
特点:Vue3 中的 watch 只能监视以下四种数据:

1.ref 定义的数据。
2.reactive 定义的数据。
3.函数返回一个值(getter 函数)。
4.一个包含上述内容的数组。

watch 监听

⭐情况一

监视【ref】 直接写数据名即可,监视的是其 value 值的改变。

示例:

import { watch, ref } from 'vue';

const count = ref(0);

// 监视 ref 'count' 的变化
watch(count, (newValue, oldValue) => {
  console.log(`变化前:${oldValue} 变化后: ${newValue}`);
},{
    deep: true,       	// 深度监听 state 对象内部的变化
    immediate: true,  	// 当设置为 true 时,watch 会在开始监视后立即执行一次回调函数。
    flush: 'pre',     	// 控制副作用(如 DOM 更新)的刷新时机。可以是 'pre' 或 'post',或者一个包含这些值的数组。
    onTrack: () => {},  // 依赖项被追踪时调用
    onTrigger:() =>{},  // 依赖项变化时调用
    computed: true    	// 计算属性模式
});

⭐情况二

监视【ref】深层要手动开启深度监视

注意:
若修改的是ref定义的对象中的属性,newValue 和 oldValue 都是新值,因为它们是同一个对象。
若修改整个ref定义的对象,newValue 是新值, oldValue 是旧值,因为不是同一个对象了。

示例:

import { watch, ref } from 'vue';

const person = ref({ name: 'John', age: 30 });

// 监视 ref 'person' 的深层属性变化
watch(
  () => person.value, // 使用函数返回 ref 的 value,以确保每次都是最新的值
  (newValue, oldValue) => {
    // 回调函数会在 person 对象的属性变化时触发
    console.log(`变化前:${oldValue.name} 变化后:${newValue.name}`);
  },
  { deep: true } // 开启深度监视
);

在这个例子中:

  • person 是一个通过 ref 创建的响应式引用,它包含一个对象,该对象有 name 和 age 属性。
  • 使用 watch 函数并传入一个函数,该函数返回 person.value。这样做是因为我们需要监视 person 对象内部属性的变化,而不是 person 这个引用本身。
  • 参数 { deep: true } 开启了深度监视,这样 watch 就能够追踪到对象内部属性的变化。
  • 当 person 对象的 name 或 age 属性发生变化时,提供的回调函数会被触发。

注意事项

  • 当你监视 ref 定义的对象并开启深度监视时,newValue 和 oldValue 将代表对象内部发生变化的属性的新旧值。
  • 如果整个 ref 定义的对象被一个新的对象替换,那么 newValue 将是新对象,而 oldValue 将是旧对象。
  • 开启深度监视可能会带来性能上的考虑,因为它会增加 Vue 需要追踪的变化的数量。

⭐情况三

监视【reactive】定义的【对象类型】数据,默认开启深度监视(无法关闭)

示例:

import { reactive, watch } from 'vue';

// 使用 reactive 创建一个响应式对象
const person = reactive({
  name: 'John',
  details: {
    age: 30
  }
});

// 监视 reactive 对象的 'details.age' 属性
watch(
  () => person.details.age,
  (newValue, oldValue) => {
    console.log(`Age changed from ${oldValue} to ${newValue}`);
  }
);

在这个例子中:

  • person 是一个使用 reactive 创建的响应式对象,它包含一个名为 details 的属性,该属性本身也是一个对象,包含 age 属性。
  • 使用 watch 来监视 person.details.age 属性的变化。由于 reactive 默认进行深度监视,因此不需要额外的 deep 选项即可追踪到 details 对象内部的 age 属性变化。

注意事项

  • reactive 创建的响应式对象总是深度监视的,这意味着你无法关闭这个行为。
  • 当你使用 watch 来监视 reactive对象的属性时,即使属性是嵌套的,也不需要 deep 选项,因为深度监视是自动应用的。
  • 如果 reactive 对象的某个属性也是一个对象,并且你想要监视这个嵌套对象的属性,你可以直接使用 watch,并提供一个返回该嵌套属性的函数。

通过这种方式,Vue 3 的 reactive API 提供了一种直观且强大的方式来创建和管理响应式状态,同时 watch API 允许你监视这些状态的变化,无需担心监视的深度问题。

⭐情况四

监视响应式对象中的某个属性,且该属性是基本类型,要写成函数式
监视响应式对象中的某个属性,且该属性是对象类型,可以直接写,也能写函数,更推荐写函数


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

基本类型属性的监视

当监视响应式对象中的基本类型属性时,推荐使用函数式的方式来访问该属性的值。这是因为基本类型的属性不会触发对象的重新分配,所以每次获取的都是最新的值。

示例:

import { watch, reactive } from 'vue';

const person = reactive({ name: 'John' });

// 使用函数式监视响应式对象中的 'name' 属性
watch(
  () => person.name,
  (newValue, oldValue) => {
    console.log(`变化前:${oldValue} 变化后:${newValue}`);
  }
);

在这个例子中,我们通过函数 () => person.name 来获取 person 对象的 name 属性的值。每次 watch 触发时,都会调用这个函数以确保获取到最新的 name 值。

对象类型属性的监视

当监视响应式对象中的对象类型属性时,可以直接写属性名,也可以使用函数式。推荐使用函数式,尤其是当你需要监视对象内部属性的变化时。

示例:

const person = reactive({ detail: { address: '123 Main St' } });

// 使用函数式监视 'detail' 对象内部的 'address' 属性
watch(
  () => person.detail.address,
  (newValue, oldValue) => {
    console.log(`变化前: ${oldValue} 变化后:${newValue}`);
  },deep: true } // 开启深度监视,以追踪对象内部属性的变化
);

在这个例子中,我们监视的是 person.detail.address。由于 address 是 detail 对象的属性,我们需要开启深度监视 { deep: true } 来确保当 address 发生变化时,watch 能够触发。
我们通过函数 () => person.name 来获取 person 对象的 name 属性的值。每次 watch 触发时,都会调用这个函数以确保获取到最新的 name 值。

⭐情况五:监视上述的多个数据

示例

import { watch, reactive, ref } from 'vue';

// 使用 reactive 创建一个响应式对象
const person = reactive({
  name: 'John',
  car: 'Toyota'
});

// 使用 ref 创建一个响应式引用
const age = ref(30);

// 监视 person 对象的 'name' 属性和 age 引用
watch([() => person.name, age], (newValues, oldValues) => {
  // newValues 和 oldValues 都是数组,分别包含新旧值
  console.log(`Name changed to ${newValues[0]}, Age changed to ${newValues[1]}`);
  // 如果只想监视 person.car 的变化,可以这样写:
  // watch([() => person.car, age], callback, options)
}, { deep: true });

在这个例子中:

  • 使用 reactive 创建了一个响应式对象 person,它包含 name 和 car 属性。
  • 使用 ref 创建了一个响应式引用age。 使用 watch 来监视 person.name 和 age。
  • 这里通过传递一个数组给 watch的第一个参数来实现同时监视多个数据源。数组中的每个元素都是一个返回要监视数据的函数或响应式引用。
  • newValues 和oldValues 参数都是数组,它们包含了所有监视数据源的新旧值。数组中每个元素的顺序与 watch 第一个参数中的顺序相对应。
  • { deep: true } 表示对 person 对象进行深度监视,这样可以确保当对象内部的属性变化时,也能触发 watch
    的回调函数。

注意事项

  • 当监视多个响应式数据源时,确保 newValues 和 oldValues 的索引与 watch 第一个参数中数据源的顺序相匹配。
  • 使用deep: true 选项可以确保当监视的对象或数组内部发生变化时,也能触发回调函数。
上一篇:kubernetes中Pod调度-Taints污点和污点容忍


下一篇:二叉树的性质