|
1 | | -export function provide() {} |
| 1 | +import { isFunction, warn } from 'core/util' |
| 2 | +import { currentInstance } from './currentInstance' |
2 | 3 |
|
3 | | -export function inject() {} |
| 4 | +export interface InjectionKey<T> extends Symbol {} |
| 5 | + |
| 6 | +export function provide<T>(key: InjectionKey<T> | string | number, value: T) { |
| 7 | + if (!currentInstance) { |
| 8 | + if (__DEV__) { |
| 9 | + warn(`provide() can only be used inside setup().`) |
| 10 | + } |
| 11 | + } else { |
| 12 | + let provides = currentInstance._provided |
| 13 | + // by default an instance inherits its parent's provides object |
| 14 | + // but when it needs to provide values of its own, it creates its |
| 15 | + // own provides object using parent provides object as prototype. |
| 16 | + // this way in `inject` we can simply look up injections from direct |
| 17 | + // parent and let the prototype chain do the work. |
| 18 | + const parentProvides = |
| 19 | + currentInstance.$parent && currentInstance.$parent._provided |
| 20 | + if (parentProvides === provides) { |
| 21 | + provides = currentInstance._provided = Object.create(parentProvides) |
| 22 | + } |
| 23 | + // TS doesn't allow symbol as index type |
| 24 | + provides[key as string] = value |
| 25 | + } |
| 26 | +} |
| 27 | + |
| 28 | +export function inject<T>(key: InjectionKey<T> | string): T | undefined |
| 29 | +export function inject<T>( |
| 30 | + key: InjectionKey<T> | string, |
| 31 | + defaultValue: T, |
| 32 | + treatDefaultAsFactory?: false |
| 33 | +): T |
| 34 | +export function inject<T>( |
| 35 | + key: InjectionKey<T> | string, |
| 36 | + defaultValue: T | (() => T), |
| 37 | + treatDefaultAsFactory: true |
| 38 | +): T |
| 39 | +export function inject( |
| 40 | + key: InjectionKey<any> | string, |
| 41 | + defaultValue?: unknown, |
| 42 | + treatDefaultAsFactory = false |
| 43 | +) { |
| 44 | + // fallback to `currentRenderingInstance` so that this can be called in |
| 45 | + // a functional component |
| 46 | + const instance = currentInstance |
| 47 | + if (instance) { |
| 48 | + // #2400 |
| 49 | + // to support `app.use` plugins, |
| 50 | + // fallback to appContext's `provides` if the instance is at root |
| 51 | + const provides = instance.$parent && instance.$parent._provided |
| 52 | + |
| 53 | + if (provides && (key as string | symbol) in provides) { |
| 54 | + // TS doesn't allow symbol as index type |
| 55 | + return provides[key as string] |
| 56 | + } else if (arguments.length > 1) { |
| 57 | + return treatDefaultAsFactory && isFunction(defaultValue) |
| 58 | + ? defaultValue.call(instance) |
| 59 | + : defaultValue |
| 60 | + } else if (__DEV__) { |
| 61 | + warn(`injection "${String(key)}" not found.`) |
| 62 | + } |
| 63 | + } else if (__DEV__) { |
| 64 | + warn(`inject() can only be used inside setup() or functional components.`) |
| 65 | + } |
| 66 | +} |
0 commit comments