fix(inject): fix support for inject option default function

fix #2050
This commit is contained in:
Evan You 2020-09-04 12:00:37 -04:00
parent 6dbc6c4cd0
commit d4724619fc
3 changed files with 47 additions and 42 deletions

View File

@ -241,7 +241,7 @@ describe('api: options', () => {
})
test('provide/inject', () => {
const Root = {
const Root = defineComponent({
data() {
return {
a: 1
@ -253,45 +253,38 @@ describe('api: options', () => {
}
},
render() {
return [h(ChildA), h(ChildB), h(ChildC), h(ChildD)]
return [h(ChildA), h(ChildB), h(ChildC), h(ChildD), h(ChildE)]
}
} as any
const ChildA = {
inject: ['a'],
render() {
return this.a
}
} as any
const ChildB = {
// object alias
inject: { b: 'a' },
render() {
return this.b
}
} as any
const ChildC = {
inject: {
b: {
from: 'a'
}
},
render() {
return this.b
}
} as any
const ChildD = {
inject: {
b: {
from: 'c',
default: 2
}
},
render() {
return this.b
}
} as any
})
expect(renderToString(h(Root))).toBe(`1112`)
const defineChild = (injectOptions: any, injectedKey = 'b') =>
({
inject: injectOptions,
render() {
return this[injectedKey]
}
} as any)
const ChildA = defineChild(['a'], 'a')
const ChildB = defineChild({ b: 'a' })
const ChildC = defineChild({
b: {
from: 'a'
}
})
const ChildD = defineChild({
b: {
from: 'c',
default: 2
}
})
const ChildE = defineChild({
b: {
from: 'c',
default: () => 3
}
})
expect(renderToString(h(Root))).toBe(`11123`)
})
test('lifecycle', async () => {

View File

@ -1,3 +1,4 @@
import { isFunction } from '@vue/shared'
import { currentInstance } from './component'
import { currentRenderingInstance } from './componentRenderUtils'
import { warn } from './warning'
@ -27,10 +28,15 @@ export function provide<T>(key: InjectionKey<T> | string, value: T) {
}
export function inject<T>(key: InjectionKey<T> | string): T | undefined
export function inject<T>(key: InjectionKey<T> | string, defaultValue: T): T
export function inject<T>(
key: InjectionKey<T> | string,
defaultValue: T,
treatDefaultAsFactory?: boolean
): T
export function inject(
key: InjectionKey<any> | string,
defaultValue?: unknown
defaultValue?: unknown,
treatDefaultAsFactory = false
) {
// fallback to `currentRenderingInstance` so that this can be called in
// a functional component
@ -41,7 +47,9 @@ export function inject(
// TS doesn't allow symbol as index type
return provides[key as string]
} else if (arguments.length > 1) {
return defaultValue
return treatDefaultAsFactory && isFunction(defaultValue)
? defaultValue()
: defaultValue
} else if (__DEV__) {
warn(`injection "${String(key)}" not found.`)
}

View File

@ -457,7 +457,11 @@ export function applyOptions(
for (const key in injectOptions) {
const opt = injectOptions[key]
if (isObject(opt)) {
ctx[key] = inject(opt.from, opt.default)
ctx[key] = inject(
opt.from,
opt.default,
true /* treat default function as factory */
)
} else {
ctx[key] = inject(opt)
}