1. Vue3侦听器核心机制解析
在Vue3的响应式系统中,侦听器(Watcher)作为核心观察者模式实现,其底层基于Proxy API重构。与Vue2的Object.defineProperty相比,Proxy可以捕获整个对象的任意属性访问和修改,包括动态添加的属性。实际开发中,我们主要通过watch和watchEffect两个API来使用侦听功能。
1.1 watch与watchEffect的差异
watch需要显式指定侦听的数据源和回调函数,适合精确控制的场景。典型用法如下:
watch(
() => state.counter,
(newVal, oldVal) => {
console.log(`计数器从${oldVal}变为${newVal}`)
},
{ immediate: true }
)
watchEffect则会自动追踪其内部使用的响应式依赖,适合需要自动收集依赖的场景:
watchEffect(() => {
console.log('当前计数:', state.counter)
// 会自动追踪state.counter的变化
})
关键区别:watch是惰性的(除非设置immediate),而watchEffect会立即执行;watch可以获取旧值,watchEffect不行;watch需要明确指定侦听源,watchEffect自动收集。
1.2 深度侦听的性能陷阱
当侦听对象类型数据时,默认是浅层侦听。如需深度侦听,需要明确设置deep选项:
watch(
() => state.userInfo,
(newVal) => {
// 处理userInfo任意层级的变化
},
{ deep: true }
)
但深度侦听会带来显著性能开销,特别是在大型对象上。实测表明,对一个包含100个属性的对象启用深度侦听,响应速度会比浅层侦听慢3-5倍。建议的优化策略:
- 尽量扁平化数据结构
- 必要时手动指定具体侦听路径而非整个对象
- 使用lodash的isEqual等函数进行新旧值对比,避免不必要的处理
2. 组件内侦听的最佳实践
2.1 Props变化的智能处理
在父子组件通信中,侦听props变化是常见需求。但直接侦听props可能导致不必要的重新渲染:
// 不推荐写法 - 可能导致过度渲染
watch(() => props.userId, fetchUserData)
// 优化方案:添加条件判断
watch(() => props.userId, (newVal) => {
if (newVal && newVal !== '') {
fetchUserData(newVal)
}
})
更优雅的方案是使用watchEffect配合条件执行:
watchEffect(() => {
if (props.userId) {
fetchUserData(props.userId)
}
})
2.2 组件生命周期与侦听器的联动
侦听器默认会绑定到组件实例,在组件卸载时自动停止。但在某些场景下需要手动管理:


206

被折叠的 条评论
为什么被折叠?



