inject 的值不响应是因为 provide 传递的是静态快照,原始类型和普通对象无法被 Vue 响应式系统追踪;只有 ref、reactive 或 computed 包裹的值才能实现响应式注入。

注入的数据默认不是响应式的,因为 Vue 的响应式系统只对在 data、setup 或 ref/reactive 中声明的值起作用。通过 provide/inject 传入的普通对象或原始值,不会被自动追踪变化。
为什么 inject 的值不响应?
provide 传递的是一个“快照”,比如直接传一个字符串、数字,或一个非 reactive 的对象,子组件 inject 后拿到的就是静态值。即使父组件 later 改变了 provide 的来源,子组件也不会更新。
- 传原始类型(如 provide('count', 1)):完全无响应
- 传普通对象(如 provide('state', { a: 1 })):属性修改不触发更新
- 只有传 ref、reactive 或 computed 才能响应
用 ref 包裹实现响应式注入
最简单可靠的方式:把需要共享的状态用 ref 或 reactive 创建,再 provide 出去,inject 后直接使用,无需额外处理。
- 父组件中:const count = ref(0); provide('count', count);
- 子组件中:const count = inject('count'); —— 直接用 count.value 读写,模板中可直接 {{ count }}
- 修改 count.value 会立即触发所有 inject 该 ref 的组件重新渲染
封装成响应式状态管理 Hook
为避免重复写 ref + provide/inject,可抽象成一个可复用的组合式函数:
- 定义 createProvideStore(() => ({ count: ref(0), name: ref('Vue') }))
- 内部自动 createScope + provide,返回一个 useStore() 供子孙调用
- 所有组件调用 useStore() 拿到的都是同一份响应式引用,改一处,处处响应
注意:避免在 inject 后解构响应式对象
常见错误:const { count } = inject('store') —— 这会丢失响应性,因为解构后变成普通变量。
- ✅ 正确:直接使用 store.count.value 或在模板中 {{ store.count }}
- ✅ 或用 toRefs(inject('store')) 解构(仅适用于 reactive 对象)
- ❌ 不要对 ref 对象做 const { x } = inject(...),否则 x 不再是 ref










