关键是要将 ref 或 reactive 等响应式引用传给 provide,inject 后必须保持引用不解构,才能实现跨层级双向响应同步;不可传普通值或二次包裹破坏响应链。

要在 provide 中传递响应式状态并实现跨层级双向同步,关键不是“让 inject 变成响应式”,而是确保 传给 provide 的值本身是响应式引用(如 ref 或 reactive),且在后代组件中正确使用 inject 获取该引用——后续对 .value 的修改或对 reactive 对象属性的变更,会自然触发依赖更新。
必须用 ref / reactive 包裹原始数据
provide 默认不处理响应性,它只是把值存进组件实例的 provides 对象。只有当你传入的是 Vue 创建的响应式对象时,其内部的 getter/setter 才能被 track 和 trigger。
- ✅ 正确:传 ref、reactive、computed 返回值等响应式包装器
- ❌ 错误:直接传普通对象、字符串、数字(如 provide('msg', 'hello'))
注入方必须保持引用,不能解构或取值后使用
inject 拿到的是响应式引用本身,一旦解构或提前 .value,就会丢失响应链接:
- ✅ 正确:
const count = inject('count')→ 后续用count.value++ - ❌ 错误:
const { value } = inject('count')或const val = inject('count').value→ 修改 val 不会更新视图
可安全传递响应式函数和上下文对象
除了基础状态,你还可以把方法、组合式逻辑封装进响应式对象一并提供:
- 例如提供一个表单上下文:
const formCtx = reactive({ model: ref({}), submit: () => { ... } }) - 再
provide('form', formCtx),子孙组件const form = inject('form')即可读写 model 并调用 submit - 注意:函数本身无需 ref,但若函数内修改了 ref/reactive 数据,响应性依然生效
避免在 provide 中返回新 ref(破坏响应链)
不要在 provide 里做类似 provide('x', ref(state.x)) 这样的“二次包裹”——这会切断与原始响应源的联系,导致父组件更新 state.x 时,注入的 ref 不同步。
- ✅ 推荐:直接
provide('x', state.x)(前提是 state.x 本身就是 ref) - ✅ 或统一用 reactive 包裹整个状态对象,再按属性注入:
provide('state', state),后代通过state.count访问


















