watch
机制详解在 Vue3 中,watch
是响应式系统的重要组成部分,用于监听数据变化并执行副作用操作。相较于 Vue2,Vue3 的 watch
在 Composition API 的支持下更加灵活,支持对多种数据类型的监听,并提供了更细粒度的控制选项。以下从核心概念、使用场景、配置选项及最佳实践等方面展开详细分析。
watch
的基本用法watch
函数接收三个参数:监听源、回调函数和配置选项。其核心语法如下:
import { watch } from 'vue';
watch(source, callback, options);
监听源(Source)
可以是以下形式:
ref
对象:watch(count, ...)
reactive
对象:watch(state, ...)
computed
)watch(() => obj.prop, ...)
watch([src1, src2], ...)
回调函数(Callback)
当监听源变化时触发,接收两个参数:
(newValue, oldValue) => { /* 逻辑 */ }
如果监听的是数组,参数为对应的数组形式:([newVal1, newVal2], [oldVal1, oldVal2])
。
配置选项(Options)
可选参数,支持以下属性:
immediate: boolean
:立即触发回调(默认 false
)。deep: boolean
:深度监听对象内部变化(默认 false
,但 reactive
对象默认深度监听)。flush: 'pre' | 'post' | 'sync'
:控制回调执行时机(默认 'pre'
,即组件更新前)。ref
)直接传递 ref
对象即可:
const count = ref(0);
watch(count, (newVal, oldVal) => {
console.log(`Count changed: ${oldVal} → ${newVal}`);
});
reactive
)由于 Vue3 对 reactive
对象默认开启深度监听,直接监听整个对象会触发所有嵌套属性的变化:
const state = reactive({ user: { name: 'Alice' } });
watch(state, (newState) => {
console.log('State changed:', newState.user.name);
});
若需监听单个属性,需使用函数返回:
watch(() => state.user.name, (newName) => {
console.log('Name changed:', newName);
});
通过数组传递多个监听源,回调参数以数组形式接收新旧值:
watch([count, () => state.user.name], ([newCount, newName], [oldCount, oldName]) => {
// 处理多个变化
});
deep
选项的用途
默认情况下,监听 reactive
对象无需开启 deep
,但若监听 ref
包裹的对象或需要显式控制深度监听时需启用:
const data = ref({ a: { b: 1 } });
watch(data, (newVal) => { /* ... */ }, { deep: true });
性能注意事项
deep
**:深度监听会遍历对象所有属性,可能影响性能。immediate: false
避免初始化时执行回调。在回调中处理异步操作时(如定时器、API 请求),需使用 onCleanup
函数清理副作用:
watch(idRef, (newId, oldId, onCleanup) => {
const timer = setTimeout(() => fetchData(newId), 1000);
onCleanup(() => clearTimeout(timer)); // 清理前一次请求
});
此机制确保在监听源频繁变化时,旧的异步操作会被及时取消,避免竞态条件。
watch
与 watchEffect
的对比特性 | watch |
watchEffect |
---|---|---|
依赖收集方式 | 显式指定监听源 | 自动追踪回调内的响应式依赖 |
初始执行 | 需配置 immediate: true |
立即执行 |
新旧值访问 | 支持 | 不支持 |
适用场景 | 精确控制监听源 | 依赖关系复杂或需自动跟踪的情况 |
表单输入验证
监听表单字段变化,实时校验并反馈:
const form = reactive({ email: '', password: '' });
watch(() => [form.email, form.password], ([email, pwd]) => {
validateEmail(email);
validatePassword(pwd);
});
路由参数变化
监听路由参数,动态加载数据:
import { useRoute } from 'vue-router';
const route = useRoute();
watch(() => route.params.id, (newId) => loadData(newId));
组合多个数据源
当多个数据共同决定某个行为时(如筛选条件):
watch([searchKeyword, filterCategory], ([keyword, category]) => {
fetchResults(keyword, category);
});
API 设计
Vue3 的 watch
通过函数式调用替代了 Vue2 的选项式配置(watch: { ... }
),更符合 Composition API 的逻辑组织方式。
性能优化
Vue3 的响应式系统基于 Proxy,减少了不必要的依赖追踪开销,且 deep
选项的行为更可控。
TypeScript 支持
Vue3 的 watch
具备更完善的类型推断,尤其在监听复杂对象时类型提示更为精准。
immediate
**:仅在需要初始数据时启用。computed
使用:将复杂逻辑封装为计算属性后再监听。通过合理利用 watch
,开发者可以构建高效、响应迅速的应用逻辑,同时保持代码的可维护性。