📚前端面试题速记
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 一个 refreactive 对象,后代 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'))