provide/inject 是 Vue 跨层级依赖注入机制,祖先组件用 provide 广播数据(推荐返回对象的函数),后代组件用 inject 订阅,支持响应式且避免传参地狱。

在 Vue 应用中,当组件嵌套很深(比如 5 层以上),通过 props 一层层往下传,或用事件一层层往上传,会非常繁琐、易错、难维护——这就是常说的“传参地狱”。provide/inject 是 Vue 提供的**跨层级依赖注入机制**,它不依赖组件树路径,只要父组件 provide 了,任意深度的后代组件都可以 inject 使用,天然适合解决深层通信问题。
provide 的写法:在祖先组件中“广播”数据
provide 可以是对象或函数。推荐用 返回对象的函数,这样能确保每次创建新实例时提供独立响应式数据(尤其配合 setup() 时):
export default {
setup() {
const userInfo = ref({ name: '张三', role: 'admin' })
const updateRole = (newRole) => {
userInfo.value.role = newRole
}
// ✅ 响应式 + 避免共享引用问题
provide('userContext', {
userInfo,
updateRole
})
return () => <div>Header</div>
}
}
inject 的写法:在任意后代组件中“订阅”数据
inject 接收 key(字符串)和可选默认值。注意:inject 返回的值不是响应式代理本身,而是原始响应式对象(如 ref 或 reactive),所以要正确使用 .value 或展开操作:
- 如果 provide 的是
ref,inject 后需用.value读取或修改 - 如果 provide 的是
reactive对象,inject 后可直接访问属性(已是响应式) - 建议统一用
ref包裹复杂对象,便于控制响应性边界
避免常见陷阱:作用域与响应性
provide/inject 不是“全局变量”,它的作用域由组件实例决定:
- 子组件 inject 到的是其最近的 provide 父组件的数据,支持多级覆盖(类似 CSS 继承)
- 不要在 provide 中直接传普通对象(如
{ count: 0 }),它不会响应式更新;必须用ref、reactive或computed - 如果 inject 在
setup()外使用(如 Options API),需在created或beforeCreate中调用,且不能在data中直接用
进阶技巧:封装成可复用的组合式函数
把 provide/inject 逻辑抽成 composable,让上下文更清晰、类型更安全(尤其搭配 TypeScript):
// composables/useUserContext.js
import { provide, inject, Ref } from 'vue'
const UserContextKey = Symbol('UserContext')
export function provideUserContext(userInfo: Ref<User>, updateRole: (r: string) => void) {
provide(UserContextKey, { userInfo, updateRole })
}
export function useUserContext() {
const context = inject(UserContextKey)
if (!context) throw new Error('useUserContext must be used within UserProvider')
return context
}
这样既避免字符串 key 拼写错误,又支持 IDE 自动跳转和类型推导,深层组件只需 const { userInfo } = useUserContext() 即可安全使用。


















