Vue响应式系统是组件通信生效的底层引擎:props依赖其完成自动更新与依赖收集,传入ref/reactive才具响应性,普通对象或字面量会中断链路;子组件不可修改props(只读代理);深层嵌套变更可精准通知;事件、provide/inject、store等均由此驱动联动更新。

Vue 响应式系统不是组件通信的“传输管道”,而是所有通信方案得以生效的底层引擎——它不决定“谁和谁说话”,但决定了“话一出口,谁立刻听见、听清多少、要不要重说一遍”。
响应式是 props 通信生效的前提
props 看似只是数据传递,实则依赖响应式系统完成三件事:父组件变更时自动触发子组件更新、子组件模板中对 prop 的读取被自动收集为依赖、prop 内部嵌套属性(如 user.profile.name)的变化也能精准通知到使用该字段的组件部分。若传入的是普通对象或字面量(如 title="Hello"),响应式链路即中断,子组件不会随父更新。
- 必须用 ref / reactive / computed 作为 prop 源,否则无响应
- 子组件内直接修改 props 会报错(只读代理),这是响应式约束而非 bug
- 深层嵌套对象变更能触发更新,得益于 Proxy 的递归拦截能力
响应式放大了事件与状态通信的联动成本
当使用 defineEmits 或 mitt 发送事件后,若事件处理逻辑涉及响应式状态变更(如更新 store 中的 ref),整个响应式链条会立即激活:emit → 父组件状态变 → 所有依赖该状态的组件重新求值 → 视图 patch。一次事件可能引发数十个组件的依赖重计算,尤其在全局状态被广泛注入时。
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 避免在事件回调中直接修改大型 reactive 对象,优先更新具体字段
- 高频 emit(如拖拽、滚动)应搭配防抖或节流,防止响应式调度队列积压
- 使用
shallowRef或markRaw隔离不需要响应的复杂数据(如第三方图表实例)
provide/inject 的性能敏感点全在响应式设计上
inject 不是“取值快慢”的问题,而是“取完之后是否持续监听”的问题。如果 provide 的是一个 ref 或 computed,每个 inject 它的组件都会将其加入自己的依赖图;哪怕只读取一次,只要该 ref 后续变化,组件就会参与更新。
立即学习“前端免费学习笔记(深入)”;
- 全局 provide 应尽量用
readonly()包裹,禁止下游意外修改 - 避免
provide('user', reactive({ name: 'a', token: 'b' })),改用provide('userName', userNameRef)按需提供 - 默认值工厂函数(
inject(key, () => init()))若返回响应式对象,也会被纳入依赖追踪
响应式让跨组件同步变得“隐式但昂贵”
在 Pinia 或自定义 store 场景中,看似只是“一个 state 被多个组件读取”,实际是每个组件都独立建立了对该 state 的响应式连接。state 变更时,所有订阅者同步触发 effect 重执行,而非按需通知。这在 50+ 组件监听同一字段时尤为明显。
- 用
computed(() => store.count)替代直接store.count,可利用 computed 缓存减少重复求值 - 对只读展示场景,考虑用
toRef(store, 'count')显式声明依赖粒度 - 组件卸载前,确保未清理的 watchEffect 或 computed 不再持有响应式引用,防止内存泄漏

















