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>