Q20
★ ★ ★ ★ ★
如何理解 Vue 3 中的 provide 和 inject?如何实现的?
⚡ 速记答案(30 秒)
祖先组件调用 provide(key, value) 暴露数据。任意后代组件用 inject(key) 获取;Vue 内部沿组件树向上查找最近一次 provide。
📖 详细讲解
标准面试回答(推荐记住)
provide 和 inject 用于跨层级组件通信。祖先组件通过 provide 提供数据,后代组件通过 inject 注入。Vue 内部会沿组件树向上查找最近的 provide。如果提供的是响应式数据,注入后仍保持响应性。推荐用 Symbol 作为 key 避免命名冲突。
原型链查找机制
Vue 组件实例在内部维护了一个 provides 对象。
- 当组件调用
provide时,它会将内容存入自己的provides对象。 - 默认情况下,组件的
provides对象继承自父组件的provides对象(通过Object.create())。 - 当调用
inject时,Vue 会直接读取当前组件实例的 父组件 的provides对象。
为什么是父组件?
因为当前组件 provide 的内容只对 子组件 可见,自己是无法 inject 自己 provide 的内容的。
响应式
Provide 本身并不处理响应式。
- 如果 provide 一个
ref或reactive对象,后代 inject 到的就是这个响应式对象。 - 只有这样,后代才能感知到数据的变化。
✅ 面试要点
- •理解 provide/inject 的查找机制
- •知道响应式数据的传递
- •掌握 Symbol key 的最佳实践
💻 代码示例
provide/inject 用法
// keys.ts - 使用 Symbol 作为 key
import type { InjectionKey, Ref } from 'vue'
export const ThemeKey: InjectionKey<Ref<string>> = Symbol('theme')
export const UserKey: InjectionKey<{ name: string }> = Symbol('user')
// 祖先组件
import { provide, ref } from 'vue'
import { ThemeKey } from './keys'
const theme = ref('dark')
provide(ThemeKey, theme) // 提供响应式数据
// 后代组件
import { inject } from 'vue'
import { ThemeKey } from './keys'
const theme = inject(ThemeKey) // 类型安全
// 带默认值
const theme = inject(ThemeKey, ref('light'))