watch

参数列表

  1. 第一个参数:要监听的数据(获取值的函数ref 返回的对象reactive 返回的对象数组);
  2. 第二个参数:监听到的数据变化后执行的函数,这个函数有两个参数分别是「旧值」和「新值」;
  3. 第三个参数:选项对象包含 deepimmediate
    • 默认初始时不执行回调, 但可以通过配置 immediatetrue, 来指定初始时立即执行第一次;
    • 通过配置 deeptrue, 来指定深度监视;

监视 ref 所定义的单个响应式数据

<script>
import { computed, reactive, watch, ref } from 'vue';
export default {
  setup() {
    const fullName = ref('张三');

    watch(fullName, (newValue, oldValue) => {
      // 数据发生改变了  张三 李四
      console.log('数据发生改变了', oldValue, newValue);
    });

    return {
      fullName,
    };
  },
};
</script>

监视 ref 所定义的多个响应式数据

<script>
import { computed, reactive, watch, ref } from 'vue';
export default {
  setup() {
    const fullName = ref('张三');
    const age = ref(20);

    watch([fullName, age], (newValue, oldValue) => {
      // 数据发生改变了  ['张三', 20]  ['李四', 20]
      console.log('数据发生改变了', oldValue, newValue);
    });

    return {
      fullName,
      age,
    };
  },
};
</script>

监视 reactive 所定义的响应式数据:

在这种情况下,watch 属性是强制开启深度监视的,无论数据有多少层,只要数据一改变,在 Vue3 中都是能被监视到的;但是在 Vue2 中,如果不开启深度监视的话,watch 属性是无法监视到深层次数据的改变的;

<script>
import { computed, reactive, watch, ref } from 'vue';
export default {
  setup() {
    const mankind = reactive({
      name: '张三',
      age: 18,
      family: {
        brother: {
          one: '李四',
        },
      },
    });

    watch(
      mankind,
      (newValue, oldValue) => {
        console.log('数据发生改变了', oldValue, newValue);
      });
        

    return {
      mankind,
    };
  },
};
</script>

监视 reactive() 所定义的响应式数据中的某一个属性

<script>
import { computed, reactive, watch, ref } from 'vue';
export default {
  setup() {
    const mankind = reactive({
      name: '张三',
      age: 18,
      family: {
        brother: {
          one: '李四',
        },
      },
    });

    watch(
      () => mankind.name,
      (newValue, oldValue) => {
        // 数据发生改变了 张三 张三1
        console.log('数据发生改变了', oldValue, newValue);
      }
    );

    return {
      mankind,
    };
  },
};
</script>

监视 reactive() 所定义的响应式数据中的多个属性的改变

<script>
import { computed, reactive, watch, ref } from 'vue';
export default {
  setup() {
    const mankind = reactive({
      name: '张三',
      age: 18,
      family: {
        brother: {
          one: '李四',
        },
      },
    });

    watch(
      [
        () => mankind.name,
        () => mankind.age
      ],
      (newValue, oldValue) => {
        // 数据发生改变了  ['张三', 18] ['张三1', 18]
        console.log('数据发生改变了', oldValue, newValue);
      });

    return {
      mankind,
    };
  },
};
</script>

监视 reactive() 和 ref 定义的响应式数据中的多个属性的改变

<script>
import { computed, reactive, watch, ref } from 'vue';
export default {
  setup() {
    const name = ref('王麻子');
    const mankind = reactive({
      name: '张三',
      age: 18,
      family: {
        brother: {
          one: '李四',
        },
      },
    });

    watch(
      [
        () => mankind.name,
        () => mankind.age,
        name
      ],
      (newValue, oldValue) => {
        // 数据发生改变了 ['张三', 18, '王麻子'] ['张三', 18, '王麻子1']
        console.log('数据发生改变了', oldValue, newValue);
      });

    return {
      mankind,
      name
    };
  },
};
</script>

watchEffect

  • watch 函数的简化版,接收一个函数作为参数,监听 「函数内响应式数据」 的变化;

  • watch 相似都可以监听一个数据源,但是 watchEffect 会在初始化的时候调用一次,与 watchimmediate 类似;

  • watchEffect 是微任务

watchEffect:立即运行一个函数,然后被动地追踪它的依赖,当这些依赖改变时重新执行该函数;

<script>
import { ref, watchEffect } from 'vue';
export default {
  setup() {
    const count = ref(0);
    const count2 = ref(0);

    watchEffect(() => {
      console.log(count.value);
      console.log(count2.value);
    });

    setTimeout(() => {
      count.value++;
      count2.value++;
    }, 1000);

    return { count, count2 };
  },
};
</script>

清除副作用

onInvalidate 被调用的时机很微妙:它只作用于异步函数,并且只有在如下两种情况下才会被调用:

  • 当 effect 函数被重新调用时;
  • 当监听器被注销时(如组件被卸载了);
<template>
  <!-- 开发中需要在侦听函数中执行网络请求,但在网络请求还没达到时停止了侦听器,或者侦听器侦听函数被再次执行了,那么上一次的网络请求应该被取消掉这个时候可以清除上一次的副作用 -->
  <div>
    <p>{{name}}</p>
    <p>{{age}}</p>
    <button @click="updataName">改变</button>
  </div>
</template>
<script>
import { ref, watchEffect } from 'vue';
export default {
  setup() {
    const name = ref('why');
    const age = ref(18);

    const stop = watchEffect(onInvalidate => {
      const timer = setTimeout(() => {
        console.log('网络请求成功');
      }, 2000);

      onInvalidate(() => {
        clearTimeout(timer);
      });
      
      console.log('name:', name.value, 'age:', age.value);
    });

    const updataName = () => {
      name.value = 'wangwy';
      age.value++;
    };

    return {
      updataName,
      name,
      age,
    };
  },
};
</script>

返回值(停止侦听):

副作用是随着组件加载而发生的,那么组件卸载时,就需要清理这些副作用;
watchEffect 的返回值 StopHandle 依旧是一个函数,就是用在这个时候,可以在 setup 函数里显式调用,也可以在组件被卸载时隐式调用;

<script>
import { ref, watchEffect } from 'vue';
export default {
  setup() {
    const stopHandle = watchEffect(() => {
      /* ... */
    });
    // 之后
    stopHandle();
  },
};
</script>

watchPostEffect

  1. 基本用法:

    watchEffect(callback, {
      flush: 'post'
    })
    
    // 或
    watchPostEffect(callback)
    
  2. 特点:

    1. 在组件更新后执行;
    2. 适用于需要访问 DOM 的场景;
    3. 等同于 Vue 2this.$nextTick 行为;
  3. 使用场景:需要在 DOM 更新后执行副作用时使用;

  4. 示例:

    watchPostEffect(() => {
      // 可以安全访问更新后的 DOM
      console.log(document.getElementById('my-element').textContent)
    })
    

watchSyncEffect

  1. 基本用法:

    watchEffect(callback, {
      flush: 'sync'
    })
    // 或
    watchSyncEffect(callback)
    
  2. 特点:

    1. 在依赖变更时同步执行;
    2. 响应速度最快,但可能导致不一致的状态;
    3. 谨慎使用,通常只在特殊场景需要;
  3. 使用场景:需要在同一事件循环内同步执行副作用时使用;

  4. 示例:

    watchSyncEffect(() => {
      // 会立即同步执行
      console.log('Sync effect:', count.value)
    })
    

多种 watch 对比

特性 watch watchEffect watchPostEffect watchSyncEffect
依赖收集方式 显式指定 自动收集 自动收集 自动收集
初始执行 可选(immediate) 总是 总是 总是
执行时机 pre (默认) pre (默认) post sync
访问旧值 可以 不可以 不可以 不可以
主要用途 精确侦听 副作用 DOM 操作 同步响应

性能优化

  1. 性能敏感场景:

    • 避免在 watcher 中执行昂贵操作;
    • 考虑使用 debouncethrottle
  2. 清理副作用:

    watchEffect((onCleanup) => {
      const timer = setInterval(() => {...}, 1000)
      onCleanup(() => clearInterval(timer))
    })
    
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

你好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. watch
    1. 1.1. 监视 ref 所定义的单个响应式数据
    2. 1.2. 监视 ref 所定义的多个响应式数据
    3. 1.3. 监视 reactive 所定义的响应式数据:
    4. 1.4. 监视 reactive() 所定义的响应式数据中的某一个属性
    5. 1.5. 监视 reactive() 所定义的响应式数据中的多个属性的改变
    6. 1.6. 监视 reactive() 和 ref 定义的响应式数据中的多个属性的改变
  2. 2. watchEffect
    1. 2.1. watchEffect:立即运行一个函数,然后被动地追踪它的依赖,当这些依赖改变时重新执行该函数;
    2. 2.2. 清除副作用
    3. 2.3. 返回值(停止侦听):
  3. 3. watchPostEffect
  4. 4. watchSyncEffect
  5. 5. 多种 watch 对比
  6. 6. 性能优化