setup 中 provide/inject 必须顶层同步调用,provide 用 Symbol 键配 ref/reactive 值,inject 需传相同键、避免解构 ref、建议设默认值,适用于祖→后代单向受控通信,不替代状态管理库。

Vue 3 的 setup 函数是组合式 API 的入口,provide 和 inject 必须在其中调用才能生效 —— 它们不是选项式写法,也不能在 data、methods 或异步回调里使用。
祖先组件中用 provide 提供数据
在祖先组件的 setup() 顶层同步调用 provide,传入唯一 key 和可响应的值:
- key 推荐用
Symbol(如const themeKey = Symbol('theme')),避免字符串冲突,尤其在插件或多人协作中 - 值要是响应式的,必须包裹为
ref或reactive;直接传普通对象,后代拿到的是静态快照,改了不更新 - 可以同时提供数据和修改函数,例如:
provide(themeKey, { color: ref('blue'), setColor: (c) => color.value = c }) - 不能写在
if分支、setTimeout或 Promise 回调里 ——provide必须同步执行,否则后代inject会找不到
后代组件中用 inject 接收数据
在任意后代组件的 setup() 顶层调用 inject,注意三点:
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- key 必须和
provide时完全一致(类型、值都相同),Symbol比字符串更可靠 - 如果注入的是
ref,不能解构使用(如const { color } = inject(themeKey)会丢失响应性),应保持theme.color.value或用toRef提取 - 建议始终传默认值,防止祖先未提供时出错:
const theme = inject(themeKey, { color: ref('light') }),或用工厂函数初始化复杂默认值
常见搭配:数据 + 方法一起注入
不只是传值,还能把修改逻辑一并暴露出去,实现“受控但解耦”的通信:
立即学习“前端免费学习笔记(深入)”;
- 祖先组件提供:
const count = ref(0)<br>provide('counter', { count, increment: () => count.value++ }) - 后代组件注入:
const { count, increment } = inject('counter') // 注意:这里能解构,因为 counter 是对象,不是 ref - 模板中直接用:
<button @click="increment">+1</button><p>{{ count }}</p>
适用边界要清楚
provide/inject 是轻量级依赖传递机制,不是万能方案:
- 只支持祖→后代单向通信,兄弟组件之间无法互通
- 不替代 Pinia/Vuex —— 它不管理状态生命周期、不支持调试工具、无模块划分能力
- 注入值本身不自动响应,但注入的
ref或其属性是响应的;修改仍需通过响应式方式触发更新

















