介绍
watch:显式指定依赖源,主动告诉框架要监听谁,依赖需要手动罗列
watchEffect:自动收集依赖,函数内部用到哪些响应式变量,就自动监听哪些,无需手动传源
语法
watch
import { ref, watch } from 'vue'
const count = ref(0)
// 第一个参数:监听源(单个/数组/函数)
watch(count, (newVal, oldVal) => {
console.log('count变了', newVal, oldVal)
}, { deep: true, immediate: true })
- 监听源支持:
ref、reactive、getter函数、多个源数组 - 回调参数自带
新值、旧值
watchEffect
import { ref, watchEffect } from 'vue'
const count = ref(0)
const name = ref('张三')
watchEffect(() => {
// 内部用到count、name,自动收集为依赖
console.log(count.value, name.value)
})
- 无需传入监听源,函数内访问的响应式数据自动成为依赖
- 回调没有旧值,只能拿到最新值
差异
| 对比维度 | watch | watchEffect |
|---|---|---|
| 依赖收集 | 手动声明监听源 | 自动收集函数内所有响应式依赖 |
| 回调参数 | (新值, 旧值) | 仅能获取最新值,无oldVal |
| 初始执行 | 默认不执行,需配置 immediate: true 才初始化触发 |
默认初始化立刻执行一次 |
| 深度监听 | 监听对象/数组需手动加 deep: true |
自动深层监听内部属性,无需deep |
| 多数据监听 | 传入数组 watch([a,b], cb) |
函数内直接同时使用a、b即可,自动监听 |
| 精准控制 | 可精准指定只监听某一个变量,无关数据变化不触发 | 只要函数内任意依赖变动都会触发,粒度更粗 |
| 停止监听 | 返回停止函数 const stop = watch(...) stop() |
返回停止函数 const stop = watchEffect(...) stop() |
| 清除副作用 | 回调第三个参数 onCleanup |
回调参数直接接收 onCleanup |
副作用清除示例
watch
watch(searchKey, (newVal, oldVal, onCleanup) => {
const timer = setTimeout(() => { /* 请求 */ }, 500)
onCleanup(() => clearTimeout(timer))
})
watchEffect
watchEffect((onCleanup) => {
const timer = setTimeout(() => {}, 500)
onCleanup(() => clearTimeout(timer))
})
适用场景
什么时候用 watch
- 需要新旧值对比做逻辑(比如判断数值增减)
- 只监听某一个/少数几个变量,希望其他变量变化不触发回调(精准控制)
- 不需要初始化执行,只在数据修改后触发(不配置immediate)
- 监听 props、路由、单独状态,逻辑和指定数据源强绑定
什么时候用 watchEffect
- 依赖多、不想手动罗列一堆监听源,简化代码
- 逻辑依赖多个响应式变量,任意一个变化都要重新执行
- 初始化就需要执行一次逻辑(接口请求、初始化计算)
- 不需要旧值,只需要基于最新状态执行操作
总结
- watch:手动指定依赖,有新旧值,默认不初始化,适合精准监听单一数据
- watchEffect:自动收集依赖,无旧值,初始化自动执行,适合多依赖聚合逻辑