1️⃣ watch 的使用和几种情况

2️⃣ 情况一:侦听单个 ref 的响应式数据

侦听单个 ref 数据直接作为第一个参数传入

  1. setup() {
  2. let num = ref(100);
  3. watch(
  4. num,
  5. (newValue, oldValue) => {
  6. console.log(`new:${newValue}`);
  7. console.log(`old:${oldValue}`);
  8. },
  9. { immediate: true }
  10. );
  11. return { num1, num2 };
  12. },

image.png
35.gif

2️⃣ 情况二:侦听多个 ref 的响应式数据

侦听多个 ref 数据时参数为数组模式

  1. setup() {
  2. let num1 = ref(100);
  3. let num2 = ref(200);
  4. watch(
  5. [num1, num2],
  6. (newValue, oldValue) => {
  7. console.log("new", newValue);
  8. console.log("old", oldValue);
  9. },
  10. { immediate: true }
  11. );
  12. return { num1, num2 };
  13. },

image.png
36.gif

2️⃣ 情况三:侦听 reactive 响应式数据

箭头 reactive 定义的响应式数据

  1. 1. 若 watch 侦听的是 reactive 定义的响应式数据,则无法正确获得 oldValue
  2. 1. 下面例子中 oldValue 和 newValue 的值是一样的
  3. 2. 若 watch 侦听的是 reactive 定义的响应式数据,则强制开启深度侦听
  4. 1. 下面例子中更高数据的最深层次依旧可以被 watch 侦听到
  5. 3. 原因:可能是因为 reactive 使用的是 proxy 封装的响应式数据,所以 reactive 的数据的 oldValue 和 newValue 是一样的,而 proxy 本身就是深度的,所以在 Vue3 中 watch 侦听 reactive 数据就是深度的
  1. setup() {
  2. let msg = reactive({
  3. num1: 100,
  4. num2: 200,
  5. obj1: {
  6. obj2: {
  7. num3: 300,
  8. },
  9. },
  10. });
  11. watch(
  12. msg,
  13. (newValue, oldValue) => {
  14. console.log("new", newValue);
  15. console.log("old", oldValue);
  16. },
  17. { immediate: true }
  18. );
  19. return { msg };
  20. },

image.png
37.gif

2️⃣ 情况四:侦听 reactive 响应式数据中的单个非对象数据

侦听 reactive 响应式数据中的单个非对象数据直接作为第一个参数传入

  1. setup() {
  2. let msg = reactive({
  3. num1: 100,
  4. num2: 200,
  5. obj1: {
  6. obj2: {
  7. num3: 300,
  8. },
  9. },
  10. });
  11. watch(
  12. () => msg.num1,
  13. (newValue, oldValue) => {
  14. console.log("new", newValue);
  15. console.log("old", oldValue);
  16. }
  17. );
  18. return { msg };
  19. },

image.png
38.gif

2️⃣ 情况五:侦听 reactive 响应式数据中的单个对象数据

根据情况三的原因,Vue3 中使用的是 proxy 所以 reactive 响应式数据本身就是深度的,但是 proxy 内部的对象并非是 proxy 代理的,所以在侦听 reactive 响应式数据中的单个对象数据时,这单个对象就并非是 proxy 代理的,所以并不会像直接侦听 reactive 数据一样强制开启 deep ,而是需要手动开启才可以深度侦听

  1. setup() {
  2. let msg = reactive({
  3. num1: 100,
  4. num2: 200,
  5. obj1: {
  6. obj2: {
  7. num3: 300,
  8. },
  9. },
  10. });
  11. watch(
  12. () => msg.obj1,
  13. (newValue, oldValue) => {
  14. console.log("new", newValue);
  15. console.log("old", oldValue);
  16. },
  17. { deep: true }
  18. );
  19. return { msg };
  20. },

image.png
40.gif

2️⃣ 情况六:侦听 reactive 响应式数据中多个非对象数据

侦听 reactive 响应式数据中多个非对象数据时参数为数组模式

  1. setup() {
  2. let msg = reactive({
  3. num1: 100,
  4. num2: 200,
  5. obj1: {
  6. obj2: {
  7. num3: 300,
  8. },
  9. },
  10. });
  11. watch([() => msg.num1, () => msg.num2], (newValue, oldValue) => {
  12. console.log("new", newValue);
  13. console.log("old", oldValue);
  14. });
  15. return { msg };
  16. },

image.png
39.gif

1️⃣ watch 的 value

image.png

1️⃣ watchEffect

watchEffect 使用同 watch 一样,不同的是 watchEffect 会默认配置 immediate 为 true,初始执行一次,默认初始时就会执行第一次, 从而可以收集需要监视的数据
watch 的套路是要指明监视的属性,也要指明监视的回调
watchEffect 的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性
watchEffect 有点像 computed:

  1. 1. 但 computed 注重的是计算出来的值( 回调函数的返回值 ),所以必须要写返回值
  2. 2. 而 watchEffect 更注重的是过程( 回调函数的函数体 ),所以不用写返回值
  1. // watchEffect 所指定的回调中用到的数据只要发生变化 则直接重新执行回调
  2. watchEffect(()=>{
  3. // ......
  4. })
  1. watchEffect 需要注意的是当你侦听一个对象时,即时我们修改了对象中的数据也不会触发 watchEffect ,因为 watchEffect 收集的是对象本身,而非对象的深度侦听,所以使用 watchEffect 时需直接 watchEffect 到值本身。如果我们需要侦听一个对象,推荐使用 watch。<br />一下代码中, watch 可以侦听到,watchEffect 侦听不到。
  1. <template>
  2. <div id="app">
  3. <el-button type="primary" @click="obj.a++">obj.a</el-button>
  4. <el-button type="primary" @click="obj.b.c++">obj.b.c</el-button>
  5. </div>
  6. </template>
  7. <script setup>
  8. import { reactive, watch, watchEffect } from 'vue'
  9. const obj = reactive({
  10. a: 100,
  11. b: {
  12. c: 200
  13. }
  14. })
  15. watch(obj, (newValue, lodValue) => {
  16. console.log('watch', obj);
  17. }, { immediate: true })
  18. watchEffect(() => {
  19. console.log('watchEffect', obj);
  20. })
  21. </script>