inject基础类型无法双向更新,因其按值传递无响应式连接;应传递ref或reactive对象共享响应式引用,通过.value或属性访问实现同步更新。

Inject 注入的数据默认是只读的,无法直接触发响应式更新。要实现 inject 数据的双向更新,关键不是传递原始值,而是传递一个 ref 或 reactive 对象,让 provide 和 inject 共享同一份响应式引用。
为什么直接 inject 基础类型无法双向更新?
因为 JavaScript 中基础类型(如 string、number、boolean)是按值传递的。即使你在 provide 侧修改了值,inject 侧拿到的只是初始快照,没有响应式连接。
例如:
- provide({ count: 1 }) → inject 拿到的是 1,不是响应式引用
- 后续 provide 修改 count = 2,inject 侧不会自动更新
正确做法:provide 一个 ref,inject 后解构使用 .value
在 provide 侧创建 ref,并注入整个 ref 对象(不是 .value)。inject 侧拿到的是同一个 ref 实例,读写 .value 都会触发响应和同步。
示例代码:
- Provide 侧:provide('countRef', ref(0))
- Inject 侧:const countRef = inject('countRef'),然后用 countRef.value 读写
- 任意组件修改 countRef.value,所有 inject 该 ref 的地方都会响应式更新
进阶技巧:用 reactive 包裹对象,统一管理多个状态
当需要注入多个相关状态(如表单字段),用 reactive 更清晰,避免重复声明多个 ref。
- Provide 侧:provide('formState', reactive({ name: '', age: 0 }))
- Inject 侧:const formState = inject('formState'),直接访问 formState.name 或赋值 formState.age = 25
- 注意:不能对 formState 整体重新赋值(如 formState = {...}),这会断开响应式连接
安全封装:用 computed + setter 构建受控的双向接口
若需拦截修改逻辑(比如校验、转换),可在 inject 侧用 computed 包一层,暴露 getter 和自定义 setter。
- const count = computed({ get: () => countRef.value, set: (v) => { if (v >= 0) countRef.value = v } })
- 模板中可直接用 v-model="count",既保持双向绑定,又控制赋值行为










