vue3 watchEffect和watch的使用及区别

Vue 3中的watchEffect是一个非常强大的响应式API,它允许开发者在响应式数据发生变化时自动运行一些副作用(side effects)。watchEffect与Vue中的另一个APIwatch相似,但有一些关键区别和特点。下面我会详细解释watchEffect的工作原理、使用方法以及与watch的比较。

工作原理

当你使用watchEffect时,你提供一个函数,Vue会立即执行这个函数,并跟踪函数中使用的任何响应式状态(reactive state)。当这些状态中的任何一个发生变化时,Vue将再次执行这个函数。

基本用法

在Vue组件中使用watchEffect通常如下所示:

import { watchEffect } from 'vue';

export default {
  setup() {
    // ...定义响应式状态

    watchEffect(() => {
      // ...你的副作用逻辑
    });

    // ...
  }
}

详细信息

第一个参数就是要运行的副作用函数。这个副作用函数的参数也是一个函数,用来注册清理回调。清理回调会在该副作用下一次执行前被调用,可以用来清理无效的副作用,例如等待中的异步请求 (参见下面的示例)。

第二个参数是一个可选的选项,可以用来调整副作用的刷新时机或调试副作用的依赖。

默认情况下,侦听器将在组件渲染之前执行。设置 flush: 'post' 将会使侦听器延迟到组件渲染之后再执行。详见回调的触发时机。在某些特殊情况下 (例如要使缓存失效),可能有必要在响应式依赖发生改变时立即触发侦听器。这可以通过设置 flush: 'sync' 来实现。然而,该设置应谨慎使用,因为如果有多个属性同时更新,这将导致一些性能和数据一致性的问题。

  • 返回值是一个用来停止该副作用的函数。

watchEffect(async (onCleanup) => {
  const { response, cancel } = doAsyncWork(id.value)
  // `cancel` 会在 `id` 更改时调用
  // 以便取消之前
  // 未完成的请求
  onCleanup(cancel)
  data.value = await response
})

停止侦听器:

const stop = watchEffect(() => {})

// 当不再需要此侦听器时:
stop()
选项
watchEffect(() => {}, {
  flush: 'post',
  onTrack(e) {
   // 当监听的值被追踪为依赖时触发,有几个值就会执行几次
    debugger
  },
  onTrigger(e) {
   // 当监听的值被更改时触发,执行顺序:onTrigger>onInvalidate>函数
    debugger
  }
})

特点

  1. 自动侦测依赖:与watch不同,watchEffect不需要明确指定侦听的源。Vue会自动侦测函数内部使用的响应式引用。

  2. 立即执行watchEffect的回调函数会在声明时立即执行一次,这有助于初始化副作用。

  3. 清理效果watchEffect接受一个回调函数,该回调函数可以返回一个清理(cleanup)函数,用于在副作用重新运行前清除或重置状态。

使用场景

  1. 自动更新DOM:当响应式状态改变时自动更新DOM。
  2. 与外部库集成:例如,当Vue状态改变时自动更新图表或其他UI元素。
  3. 资源清理:如取消API请求或清理定时器。

watch的比较

  • 自动侦测watchEffect自动侦测依赖,而watch需要指定特定的侦听源。
  • 执行时机watchEffect在声明时立即执行一次,而watch默认不执行,除非设置了immediate选项。
  • 适用场景watchEffect更适合于依赖多个源的复杂逻辑,而watch更适用于侦听特定的数据源并根据变化作出响应。

示例

1、让 watch 和 watchEffect 监听 reactive 定义的值:

watch:

   const state = reactive({ count: 0, attr: { name: "" } });
    watch(state, (post, pre) => {
        console.log(post);
        console.log(pre);
        console.log("watch 执行了");
    });
    const clickEvent = () => {
        state.count++;
    };

当触发 clickEvent 事件改变 state.count 的值时,我们可以从控制台中看到如下结果,说明 watch 响应了 state.count 的变化,但是在初始的时候并没有执行。

watchEffect:

    const state = reactive({ count: 0, attr: { name: "" } });
    watchEffect(() => {
        console.log("watchEffect 执行了");
        console.log(state);
    });
    const clickEvent = () => {
        state.count++;
    };

点击多次按钮触发 clickEvent 事件,控制台结果如下,说明 watchEffect 在组件第一次执行的时候执行了回调,而在之后并不再响应 state.count 的变化。

说明 watch 可以监听 reactive 定义的值,而 watchEffect 不能。

2、让 watch 和 watchEffect 监听 ref 定义的值。

    const count = ref(0);
    watch(count, (post, pre) => {
        console.log("watch 执行了");
        console.log(post);
        console.log(pre);
    });
    const clickEvent = () => {
        count.value++;
    };

初始化未执行,点击执行。

watchEffect:

    const count = ref(0);
    watchEffect(() => {
      console.log("watchEffect 执行了");
      console.log(count);
    });
    const clickEvent = () => {
      count.value++;
    };

结果同上,说明 watch 可以响应 ref 定义的值,而 watchEffect 则不能。

3、让 watch 和 watchEffect 响应单一值的变化:

    const state = reactive({ count: 0 });
    watch(state.count, (post, pre) => {
        console.log("watch 执行了");
        console.log(post);
        console.log(pre);
    });
    const clickEvent = () => {
        state.count++;
    };

结果显示无论怎么触发 clickEvent 事件,watch中的回调函数都不会触发,控制台不会打印任何内容。

watchEffect:

  const state = reactive({ count: 0 });
    watchEffect(() => {
        console.log("watchEffect 执行了");
        console.log(state.count);
    });
    const clickEvent = () => {
        state.count++;
    };

说明 watchEffect 能响应单一的值,而 watch 不能,若要让 watch 响应 count 的变化,需要给第一个参数传入 getter 函数,如下:

  const state = reactive({ count: 0 });
    watch(
        () => state.count,
        (post, pre) => {
            console.log("watch 执行了");
            console.log(post);
            console.log(pre);
        }
    );
    const clickEvent = () => {
        state.count++;
    };

如果 getter 函数 返回的是 state 引用值,而在改变 state.count 的时候并不会修改 state 的引用值,因此不会响应 state.count 的变化,如果要响应,需要传入第三个参数配置 {deep:true},同时代码中的 post 和 pre 的值是一样的,如下:

  const state = reactive({ count: 0 });
    //不会响应变化
    watch(
        () => state,
        (post, pre) => {
            console.log("watch 执行了");
            console.log(post);
            console.log(pre);
        }
    );
    const clickEvent = () => {
        state.count++;
    };
 const state = reactive({ count: 0 });
    //加上了 {deep:true} 可以响应变化
    watch(
        () => state,
        (post, pre) => {
            console.log("watch 执行了");
            console.log(post);
            console.log(pre);
        },
        {deep:true}
    );
    const clickEvent = () => {
        state.count++;
    };

若返回的是引用值,而又需要比较变化前后不同的值,则需要传入 getter 函数返回该对象的深拷贝后的值,如下例子,返回一个数组:

    const state = reactive({ count: 0 });
    const numbers = reactive([0, 1, 2, 3]);
    watch(
        () => [...numbers],
        (post, pre) => {
            console.log("watch 执行了");
            console.log(post);
            console.log(pre);
        }
    );
    const clickEvent = () => {
        numbers.push(1);
    };

以上就是vue3中的watch和watchEffect怎么用的详细内容。

  • 35
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值