provide 和 inject 是 Vue 3 中用于跨层级组件通信的 API,父组件通过 provide 提供响应式数据或方法,后代组件通过 inject 获取,推荐使用 Symbol 作 key 并配合 ref/reactive 保持响应性。

provide 和 inject 的基础用法
在 Vue 3 的 Composition API 中,provide 和 inject 是一对用于跨层级组件通信的 API。它们不依赖 props 逐层传递,也不需要事件总线或状态库,适合爷孙、甚至更深嵌套的组件间共享数据或方法。
使用时需注意:provide 在父(或祖先)组件中调用,inject 在任意后代组件中调用,两者通过相同的 key 关联。
- 父组件 setup 中调用
provide(key, value),value 建议用ref或reactive包裹以保持响应性 - 子/孙组件 setup 中调用
const value = inject(key)获取数据 - key 可以是字符串(简单场景),但更推荐 Symbol 类型(避免命名冲突),例如
Symbol('user')
实现响应式跨组件通信
provide 默认不自动响应数据变化,若想子组件随父组件数据更新而更新,必须提供响应式引用(如 ref 或 reactive 对象)。
- 在父组件中:
const userInfo = ref({ name: 'Alice', role: 'admin' }),然后provide('userInfo', userInfo) - 在子组件中:
const userInfo = inject('userInfo'),直接使用userInfo.value.name,修改userInfo.value.name = 'Bob'会同步更新所有 inject 该值的组件 - 若需提供方法(如更新逻辑),可一并放入 reactive 对象或单独 provide,例如
provide('updateUser', (newName) => { userInfo.value.name = newName })
配合 Pinia 理解其底层机制
Pinia 的 useStore() 实际就是对 inject(piniaSymbol) 的封装。它不靠 Composition API 自身实现“模式”,而是深度依托 provide/inject 这一 Vue 底层能力。
- 调用
app.use(pinia)时,Pinia 已在根组件通过provide(piniaSymbol, piniaInstance)注入实例 -
useUserStore()内部执行inject(piniaSymbol)拿到 pinia 实例,再按 store id 查找或创建 store - 非组件环境(如工具函数、测试 setup)需手动
import { piniaSymbol } from 'pinia',再inject(piniaSymbol)获取实例
常见陷阱与规避方式
错误往往出现在时机和覆盖上,而非语法本身。
- 不能在
createApp()之前或组件未挂载时调用useStore()或inject(),否则返回undefined - 切勿在任意组件中
provide(piniaSymbol, ...)—— 这会覆盖根节点注入的 pinia 实例,导致所有useStore()失效 - inject 第二个参数可设默认值,如
inject('theme', 'light'),避免未 provide 时出错 - 避免滥用:仅当跨越三层以上或多个无关子组件需共用同一份状态时才用,否则优先用 props/emits 或局部状态


















