// provide exportfunction provide<T, K = InjectionKey<T> | string | number>( key: K, value: K extendsInjectionKey<infer V> ? V : T ) { // 读取当前组件的实例(currentInstance)并做判断 if (!currentInstance) { if (__DEV__) { // 函数形式的provide只能在setup函数/语法糖模式使用,Options API无法使用 warn(`provide() can only be used inside setup().`) } } else { // 读取当前组件实例中的provides let provides = currentInstance.provides // by default an instance inherits its parent's provides object // but when it needs to provide values of its own, it creates its // own provides object using parent provides object as prototype. // this way in `inject` we can simply look up injections from direct // parent and let the prototype chain do the work. // 默认情况下,实例继承父类的provides对象 // 如果当前组件有自己的provide,它使用父provides对象作为原型创建自己的provides对象 // 在inject中,只需查询原型链即可 // 当前组件的父组件的provides const parentProvides = currentInstance.parent && currentInstance.parent.provides // 判断父组件和子组件的provides是否一样 if (parentProvides === provides) { // 如果一样的话(子组件还没有自己的provide),以父组件的provides为基础创建新对象 provides = currentInstance.provides = Object.create(parentProvides) } // TS doesn't allow symbol as index type // 在新的对象上添加这次provide的值 provides[key asstring] = value } }
// inject // 一些函数重载 exportfunction inject<T>(key: InjectionKey<T> | string): T | undefined exportfunction inject<T>( key: InjectionKey<T> | string, defaultValue: T, treatDefaultAsFactory?: false ): T exportfunction inject<T>( key: InjectionKey<T> | string, defaultValue: T | (() => T), treatDefaultAsFactory: true ): T exportfunctioninject( key: InjectionKey<any> | string, defaultValue?: unknown, treatDefaultAsFactory = false ) { // fallback to `currentRenderingInstance` so that this can be called in // a functional component // 读取当前组件实例 const instance = currentInstance || currentRenderingInstance
// also support looking up from app-level provides w/ `app.runWithContext()` // 如果能读到 if (instance || currentApp) { // #2400 // to support `app.use` plugins, // fallback to appContext's `provides` if the instance is at root // 尝试去读父组件的provides,如果实例在根目录,回退到appContext的provides中 const provides = instance ? instance.parent == null ? instance.vnode.appContext && instance.vnode.appContext.provides : instance.parent.provides : currentApp!._context.provides
if (provides && (key asstring | symbol) in provides) { // TS doesn't allow symbol as index type // 读到就直接返回 return provides[key asstring] } elseif (arguments.length > 1) { return treatDefaultAsFactory && isFunction(defaultValue) ? defaultValue.call(instance && instance.proxy) : defaultValue // 读不到就报错 } elseif (__DEV__) { warn(`injection "${String(key)}" not found.`) } } elseif (__DEV__) { warn(`inject() can only be used inside setup() or functional components.`) } }