深入理解 Vue 3 中的 watch 和 watchEffect

watchwatchEffect 是两个超实用的响应式工具,它们能帮我们处理副作用。接下来咱就详细唠唠它们的使用方法、区别以及面试考点。

一、watch 的使用

watch 这个方法主要用来监听响应式数据的变化,一旦数据有变动,就会执行相应的回调函数。它的使用场景非常广泛,比如当用户输入框里的内容改变了,我们要实时更新某个数据;或者某个状态值变化时,去触发一些异步操作。

基本用法

下面是监听单个响应式数据的例子:

javascript 复制代码
import { ref, watch } from 'vue';

const count = ref(0);

watch(count, (newValue, oldValue) => {
    console.log(`新值: ${newValue}, 旧值: ${oldValue}`);
});

count.value++; // 这里改变了count的值,会触发watch的回调函数

在这个例子里,watch 接收两个参数,第一个是要监听的响应式数据 count,第二个是回调函数,回调函数里有两个参数,newValue 是新的值,oldValue 是旧的值。

监听多个数据源

要是你想同时监听多个响应式数据,也是可以的。把要监听的数据放在一个数组里就行:

ini 复制代码
import { ref, watch } from 'vue';

const count1 = ref(0);
const count2 = ref(0);

watch([count1, count2], ([newCount1, newCount2], [oldCount1, oldCount2]) => {
    console.log(`count1新值: ${newCount1}, count1旧值: ${oldCount1}`);
    console.log(`count2新值: ${newCount2}, count2旧值: ${oldCount2}`);
});

count1.value++;
count2.value++;

这里的回调函数接收的参数也是数组形式,分别对应新值和旧值。

深度监听

如果你要监听的是一个对象,并且想在对象内部属性变化时也触发回调,就得开启深度监听:

javascript 复制代码
import { ref, watch } from 'vue';

const obj = ref({
    name: '张三',
    age: 20
});

watch(obj, (newObj, oldObj) => {
    console.log('对象发生了变化');
}, { deep: true });

obj.value.age = 21; // 改变对象内部属性,会触发回调

通过设置 { deep: true } 这个选项,就能实现深度监听了。

即时回调

有时候,我们希望在组件挂载时就执行一次回调函数,而不只是在数据变化时执行。这时候可以设置 immediate: true 选项:

javascript 复制代码
import { ref, watch } from 'vue';

const count = ref(0);

watch(count, (newValue, oldValue) => {
    console.log(`新值: ${newValue}, 旧值: ${oldValue}`);
}, { immediate: true });

这样在组件挂载时,回调函数就会马上执行一次。

二、watchEffect 的使用

watchEffect 是一个更简洁的响应式副作用函数,它会自动追踪其内部使用的所有响应式数据,只要这些数据有变化,就会重新执行回调函数。

基本用法

javascript 复制代码
import { ref, watchEffect } from 'vue';

const count = ref(0);

watchEffect(() => {
    console.log(`当前count的值是: ${count.value}`);
});

count.value++; // 改变count的值,会触发watchEffect的回调函数

在这个例子里,watchEffect 接收一个回调函数,在回调函数里使用了 count 这个响应式数据,所以当 count 的值改变时,回调函数就会重新执行。

清理副作用

watchEffect 里,我们可以返回一个清理函数,用于在回调函数重新执行或者组件卸载时做一些清理工作,比如取消定时器、取消网络请求等:

javascript 复制代码
import { ref, watchEffect } from 'vue';

const count = ref(0);

watchEffect((onInvalidate) => {
    const timer = setInterval(() => {
        console.log(count.value);
    }, 1000);

    onInvalidate(() => {
        clearInterval(timer); // 清理定时器
    });
});

count.value++;

这里的 onInvalidate 函数接收一个清理函数,当回调函数重新执行或者组件卸载时,清理函数就会被调用。

三、区别

1. 自动追踪与显式指定

watchEffect 会自动追踪其内部使用的所有响应式数据,只要这些数据有变化,就会重新执行回调函数。而 watch 需要你显式地指定要监听的数据源。比如上面 watchEffect 的例子,它会自动追踪 count 的变化;而 watch 则需要你明确告诉它要监听 count

2. 初始执行

watchEffect 会在组件挂载时立即执行一次回调函数,而 watch 默认情况下不会在组件挂载时执行回调,除非你设置了 immediate: true 选项。

3. 旧值访问

watch 的回调函数可以接收到新值和旧值,方便你对比数据的变化。而 watchEffect 没有直接提供旧值的访问方式,因为它更侧重于响应式数据的变化触发副作用,不太关注旧值。

4. 使用场景

watch 更适合用于需要对比新旧值的场景,比如当某个数据变化时,根据新旧值的不同做不同的处理;而 watchEffect 适合用于一些简单的副作用场景,只要相关数据变化就执行,不需要关心旧值。

四、基于面试

原理相关问题

面试官可能会问你 watchwatchEffect 的实现原理。简单来说,watch 是通过对指定的数据源进行依赖收集,当数据源变化时,触发对应的回调函数。而 watchEffect 是在回调函数执行时,自动收集其中使用的所有响应式数据的依赖,当这些数据变化时,重新执行回调函数。

使用场景选择

可能会给你一些具体的业务场景,让你选择用 watch 还是 watchEffect。这时候你要根据它们的区别来判断。如果需要对比新旧值,就选 watch;如果只是简单地在数据变化时执行操作,选 watchEffect

副作用清理

面试官也许会问你在 watchwatchEffect 里怎么清理副作用。在 watchEffect 里可以通过返回清理函数来实现;在 watch 里,如果你需要在组件卸载时做清理工作,可以在 beforeUnmount 钩子函数里进行。

性能方面

还可能会探讨它们对性能的影响。watchEffect 因为会自动追踪所有依赖,可能会导致一些不必要的回调执行。所以在性能敏感的场景下,使用 watch 显式指定依赖可能会更好。

相关推荐
dog shit39 分钟前
web第十次课后作业--Mybatis的增删改查
android·前端·mybatis
我有一只臭臭39 分钟前
el-tabs 切换时数据不更新的问题
前端·vue.js
七灵微43 分钟前
【前端】工具链一本通
前端
Nueuis2 小时前
微信小程序前端面经
前端·微信小程序·小程序
_r0bin_4 小时前
前端面试准备-7
开发语言·前端·javascript·fetch·跨域·class
IT瘾君4 小时前
JavaWeb:前端工程化-Vue
前端·javascript·vue.js
zhang98800004 小时前
JavaScript 核心原理深度解析-不停留于表面的VUE等的使用!
开发语言·javascript·vue.js
potender4 小时前
前端框架Vue
前端·vue.js·前端框架
站在风口的猪11085 小时前
《前端面试题:CSS预处理器(Sass、Less等)》
前端·css·html·less·css3·sass·html5
程序员的世界你不懂5 小时前
(9)-Fiddler抓包-Fiddler如何设置捕获Https会话
前端·https·fiddler