在 Vue 3 的 Composition API 中,watch 是一个非常强大的工具,用于监听响应式数据的变化并做出相应的处理。本文将通过一段实际代码来深入解析 watch 的行为和使用技巧。
🧩 示例代码回顾
ts
import { reactive, watch } from 'vue'
const state = reactive({
a: 1,
b: 2,
c: 3
})
watch(
() => {
console.log(state.a + state.b)
return state.a + state.b
},
(val) => {
console.log(val * 2)
}
)
setTimeout(() => {
state.a++
//state.b
state.b--
}, 1000)
🔍 初识 watch
基本结构
Vue 的 watch 函数接收三个参数:
- source(监听源):可以是一个响应式引用(如 ref)、一个返回值的 getter 函数、或一个包含多个源的数组。
- callback(回调函数):当 source 变化时执行的函数。
- options(可选配置) :例如
{ immediate: true, deep: true }
。
本例中的逻辑
- 我们定义了一个响应式对象 state,包含属性
a
、b
和c
。 - 使用
watch
监听state.a + state.b
的变化,并在变化时打印其两倍值。 - 在 1 秒后修改
a
和b
的值。
⚙️ 深入分析
1. 初始化阶段
当组件加载时,watch
的第一个函数会被立即调用:
ts
() => {
console.log(state.a + state.b) // 输出 3
return state.a + state.b
}
此时 a = 1
, b = 2
,所以 a + b = 3
,控制台输出 3
。
由于这是第一次运行,还没有发生任何变化,因此不会触发回调 (val) => console.log(val * 2)
。
2. 修改状态后的行为
1 秒后,执行以下操作:
ts
state.a++ // a = 2
state.b-- // b = 1
此时 a + b = 3
,与之前的值相同。
虽然 a
和 b
都发生了变化,但它们的和没有改变 ,因此 watch
回调 (val) => console.log(val * 2)
不会被触发。
但是,下面这行代码仍然会执行:
ts
console.log(state.a + state.b) // 输出 3
这是因为每次依赖项发生变化时,getter 函数都会重新执行一次以检查是否有变化。
📌 控制台输出顺序
- 页面加载时:
3
(来自watch
函数体内console.log
) - 1 秒后:
-3
(来自watch
函数体再次执行)- ❌ 不会输出
6
,因为a + b
的值没有改变
- ❌ 不会输出
🧪 如何让watch
强制触发?
如果你希望即使值不变也触发回调,可以考虑以下方式:
✅ 使用 immediate: true
ts
watch(
() => {
console.log(state.a + state.b)
return state.a + state.b
},
(val) => {
console.log(val * 2)
},
{ immediate: true }
)
这样你会看到两次 3
和一次 6
(在 setTimeout
后)。
注意:
deep: true
对基础类型无效,通常用于对象或数组。
💡 实际应用场景
watch
常用于以下场景:
- 表单验证:监听输入框内容变化
- 数据同步:当某个值变化时更新其他状态
- 异步请求:根据用户输入发起搜索请求
- 路由守卫:监听路由变化并执行相应逻辑
🧠 小结
知识点 | 内容 |
---|---|
watch 初始执行 |
会执行一次 getter 函数,但不会触发回调 |
触发回调条件 | 必须是返回值发生变化才会触发 |
控制台输出 | 即使不触发回调,getter 函数也会重新执行 |
强制首次触发 | 可使用 { immediate: true } |
📚 总结
Vue 3 的watch
提供了灵活的数据监听机制,但它的行为有时可能会让人困惑。理解它的工作原理,尤其是如何判断"变化",对于编写高效且可维护的响应式逻辑至关重要。
通过上面的例子,我们不仅掌握了watch
的基本用法,还了解了它的内部机制以及如何控制其行为。希望这篇文章能帮助你更好地理解和使用 Vue 3 的响应式系统!