Vue3 面试原理部分

一.Vue3中依赖注入原理

在创建实例时会采用父组件的provides属性

const instance: ComponentInternalInstance = {
    uid: uid++,
    provides: parent ? parent.provides : Object.create(appContext.provides),
}
1
2
3
4

ProvideAPI

provides属性会向上查找父组件provides属性

export function provide<T>(key: InjectionKey<T> | string | number, value: T) {
  if (!currentInstance) {
    if (__DEV__) {
      warn(`provide() can only be used inside setup().`)
    }
  } else {
    let provides = currentInstance.provides // 获取当前实例的provides属性
    const parentProvides =
      currentInstance.parent && currentInstance.parent.provides
    if (parentProvides === provides) { // 组件提供自己值的时候,用父组件的provides作为原型链创建新的对象
      provides = currentInstance.provides = Object.create(parentProvides)
    }
    // TS doesn't allow symbol as index type
    provides[key as string] = value
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

InjectAPI

查找provides中是否包含需要注入的属性

export function inject(
  key: InjectionKey<any> | string,
  defaultValue?: unknown,
  treatDefaultAsFactory = false
) {
  const instance = currentInstance || currentRenderingInstance
  if (instance) {
    const provides = // 获取provides值
      instance.parent == null
        ? instance.vnode.appContext && instance.vnode.appContext.provides
        : instance.parent.provides

    if (provides && (key as string | symbol) in provides) { // 如果需要注入的属性在provides中
      // TS doesn't allow symbol as index type 
      return provides[key as string] // 则将属性返回
    } else if (arguments.length > 1) { // 注入式可以采用默认参数注入
      return treatDefaultAsFactory && isFunction(defaultValue)
        ? defaultValue()
        : defaultValue
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

依赖注入时,注入的数据来源不明确。不适合在业务代码中使用,可能会带来重构复杂的问题。(一般用于编写插件使用)