深入理解 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 显式指定依赖可能会更好。

相关推荐
x-cmd9 分钟前
[250512] Node.js 24 发布:ClangCL 构建,升级 V8 引擎、集成 npm 11
前端·javascript·windows·npm·node.js
夏之小星星22 分钟前
el-tree结合checkbox实现数据回显
前端·javascript·vue.js
crazyme_636 分钟前
前端自学入门:HTML 基础详解与学习路线指引
前端·学习·html
撸猫7911 小时前
HttpSession 的运行原理
前端·后端·cookie·httpsession
亦世凡华、1 小时前
Rollup入门与进阶:为现代Web应用构建超小的打包文件
前端·经验分享·rollup·配置项目·前端分享
琉璃℡初雪1 小时前
vue2/3 中使用 @vue-office/docx 在网页中预览(docx、excel、pdf)文件
vue.js·pdf·excel
Bl_a_ck1 小时前
【React】Craco 简介
开发语言·前端·react.js·typescript·前端框架
augenstern4162 小时前
webpack重构优化
前端·webpack·重构
海拥✘3 小时前
CodeBuddy终极测评:中国版Cursor的开发革命(含安装指南+HTML游戏实战)
前端·游戏·html
寧笙(Lycode)3 小时前
React系列——HOC高阶组件的封装与使用
前端·react.js·前端框架