Vue3的watchEffect
Vue3的watchEffect
在 Vue 3 中,watchEffect 是一个强大的 API,用于自动追踪响应式数据的变化并执行副作用(side effects)。它与 watch 的主要区别在于,watchEffect 不需要显式指定要监视的响应式数据,而是会自动追踪回调函数中访问的响应式数据。
问题背景:水质监测系统
假设你正在开发一个水质监测系统,需要实时监控水温(temp)和水位(height)。具体需求如下:
-
水温监控:当水温达到或超过 60°C 时,需要向服务器发送警告请求。
-
水位监控:当水位达到或超过 80cm 时,也需要向服务器发送警告请求。
问题描述
-
水温 和 水位 是两个独立的响应式数据。
-
需要实时监控这两个数据的变化,并在满足条件时执行特定操作(如发送请求)。
-
需要一个简洁且高效的方式来实现这一功能。
实现思路
- 使用
watch:
-
watch需要显式指定要监视的数据。 -
需要手动处理多个数据的依赖关系。
-
需要手动处理回调函数中的逻辑。
- 使用
watchEffect:
-
watchEffect自动追踪回调函数中访问的响应式数据。 -
不需要显式指定依赖项,代码更简洁。
-
默认立即执行回调函数,并在依赖数据变化时重新执行。
代码实现
使用 watch 实现
HTML复制
<template>
<div>
<h1>水质监测系统</h1>
<p>当前水温:{{ temp }}°C</p>
<p>当前水位:{{ height }}cm</p>
<button @click="increaseTemp">水温 + 10°C</button>
<button @click="increaseHeight">水位 + 10cm</button>
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
const temp = ref(10); // 初始水温
const height = ref(0); // 初始水位
const increaseTemp = () => {
temp.value += 10;
};
const increaseHeight = () => {
height.value += 10;
};
watch([temp, height], ([newTemp, newHeight], [oldTemp, oldHeight]) => {
console.log(`水温从 ${oldTemp}°C 变为 ${newTemp}°C`);
console.log(`水位从 ${oldHeight}cm 变为 ${newHeight}cm`);
if (newTemp >= 60 || newHeight >= 80) {
console.log('发送警告请求到服务器');
}
});
</script>
使用 watchEffect 实现
HTML复制
<template>
<div>
<h1>水质监测系统</h1>
<p>当前水温:{{ temp }}°C</p>
<p>当前水位:{{ height }}cm</p>
<button @click="increaseTemp">水温 + 10°C</button>
<button @click="increaseHeight">水位 + 10cm</button>
</div>
</template>
<script setup lang="ts">
import { ref, watchEffect } from 'vue';
const temp = ref(10); // 初始水温
const height = ref(0); // 初始水位
const increaseTemp = () => {
temp.value += 10;
};
const increaseHeight = () => {
height.value += 10;
};
watchEffect(() => {
if (temp.value >= 60 || height.value >= 80) {
console.log('发送警告请求到服务器');
}
});
</script>
对比分析
有没有发现watchEffect比watch的代码要简单一些呢?而且watchEffect会自动分析数据的变化从而做出相应的响应,而watch需要指定具体的变量
- 代码简洁性:
-
watch:需要显式指定依赖项[temp, height],并处理回调函数中的逻辑。 -
watchEffect:自动追踪回调函数中访问的响应式数据,代码更简洁。
- 立即执行:
-
watch:默认不立即执行,需要显式指定{ immediate: true }。 -
watchEffect:默认立即执行回调函数。
- 灵活性:
-
watch:适合需要显式控制依赖项的场景。 -
watchEffect:适合简单的响应式副作用处理,自动追踪依赖项。
通过上述问题和代码实现,你可以看到 watchEffect 在处理简单逻辑时的简洁性和高效性。它自动追踪依赖项,无需显式指定,非常适合动态响应数据变化的场景。在实际开发中,你可以根据具体需求选择使用 watch 或 watchEffect,以实现更高效的数据监听和副作用管理。
watchEffect 的特点
那我们现在知道了,watchEffect 有以下特点
- 自动追踪依赖:
-
watchEffect会自动追踪回调函数中访问的响应式数据。你不需要显式指定依赖项,这使得代码更简洁、更易读。 -
例如,如果回调中访问了
ref或reactive的属性,这些属性会被自动添加为依赖。
- 立即执行:
watchEffect在组件挂载时会立即执行一次回调函数,而watch默认不会立即执行,除非显式指定{ immediate: true }。
- 响应式副作用:
- 当依赖的响应式数据变化时,
watchEffect会重新执行回调函数,确保始终获取最新的状态。
- 灵活性:
watchEffect可以与ref、reactive等响应式 API 结合使用,灵活处理不同的数据类型和结构。
watchEffect 的基本用法
JavaScript复制
import { ref, watchEffect } from 'vue';
const count = ref(0);
watchEffect(() => {
console.log(`count is now ${count.value}`);
});
在这个例子中,watchEffect 会立即执行,并在 count 变化时输出新的值。
watch 与 watchEffect 的对比
|特性|watch|watchEffect| |-|-|-| |依赖声明|需要显式指定要监听的响应式数据|自动追踪内部访问的响应式数据| |回调参数|提供 newVal 和 oldVal|无法直接访问变化前后的值| |立即执行|默认不立即执行(可通过 { immediate: true } 控制)|默认立即执行| |适用场景|适合特定数据变化时执行操作|适合简单逻辑的响应式副作用处理|
watchEffect 的原理
那它的原理是什么呢,为什么能够做到自动依赖追踪呢?
Vue 3 使用 Proxy 来实现响应式系统,这是 watchEffect 自动依赖追踪的基础。Proxy 是一个强大的 JavaScript API,可以拦截对象的操作(如读取、设置属性等),并触发相应的副作用。
(一)响应式对象的创建
JavaScript复制
import { reactive } from 'vue';
const state = reactive({
temp: 10,
height: 0
});
-
reactive函数会将对象包装成一个响应式对象。 -
Proxy会拦截对对象的读取和修改操作。
(二)响应式引用的创建
JavaScript复制
import { ref } from 'vue';
const temp = ref(10);
const height = ref(0);
ref函数会创建一个响应式引用对象,其内部使用Proxy实现。
二、依赖收集
当 watchEffect 的回调函数执行时,Vue 会自动追踪回调中访问的所有响应式数据。这些数据被添加为依赖项。
(一)自动追踪依赖
JavaScript复制
import { watchEffect } from 'vue';
watchEffect(() => {
console.log(`当前水温:${temp.value}°C`);
console.log(`当前水位:${height.value}cm`);
});
-
在回调函数中访问
temp.value和height.value时,Vue 会自动将temp和height添加为依赖项。 -
Proxy拦截了对temp和height的读取操作,并记录了这些依赖。
(二)依赖更新
-
当
temp或height的值发生变化时,Proxy会触发副作用。 -
watchEffect会重新执行回调函数,确保回调函数始终能够获取最新的数据状态。
三、重新执行回调
watchEffect 的回调函数会在以下情况下重新执行:
-
依赖项变化:当依赖的响应式数据发生变化时,
Proxy会触发副作用,watchEffect会重新执行回调函数。 -
组件挂载时:
watchEffect的回调函数会在组件挂载时立即执行一次。
(一)立即执行
JavaScript复制
watchEffect(() => {
console.log(`当前水温:${temp.value}°C`);
console.log(`当前水位:${height.value}cm`);
});
- 回调函数会在组件挂载时立即执行一次,收集依赖项。
(二)依赖项变化时重新执行
JavaScript复制
watchEffect(() => {
if (temp.value >= 60 || height.value >= 80) {
console.log('发送警告请求到服务器');
}
});
- 当
temp或height的值发生变化时,watchEffect会重新执行回调函数。
让我们来总结一下:
(一)Proxy 拦截
-
Proxy拦截对象的读取和修改操作,记录依赖项。 -
当依赖项变化时,
Proxy触发副作用。
(二)自动依赖收集
-
watchEffect的回调函数执行时,Vue 自动追踪回调中访问的响应式数据。 -
这些数据被自动添加为依赖项,无需显式指定。
(三)重新执行
-
当依赖项变化时,
watchEffect会重新执行回调函数。 -
回调函数在组件挂载时立即执行一次。
通过上述机制,watchEffect 实现了自动依赖追踪和重新执行回调的功能,使得开发者可以更简洁地处理响应式副作用。
总结
watchEffect 是 Vue 3 中处理响应式数据变化和副作用的工具之一。它自动追踪依赖,无需显式指定依赖项,适合简单逻辑的响应式副作用处理。在实际开发中,还要根据具体需求选择使用 watch 或 watchEffect,以实现更高效的数据监听和副作用管理。
- 点赞
- 收藏
- 关注作者
评论(0)