Procházet zdrojové kódy

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

fix #2050
Evan You před 5 roky
rodič
revize
d4724619fc

+ 29 - 36
packages/runtime-core/__tests__/apiOptions.spec.ts

@@ -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)]
-      }
-    } as any
-    const ChildA = {
-      inject: ['a'],
-      render() {
-        return this.a
-      }
-    } as any
-    const ChildB = {
-      // object alias
-      inject: { b: 'a' },
-      render() {
-        return this.b
+        return [h(ChildA), h(ChildB), h(ChildC), h(ChildD), h(ChildE)]
       }
-    } as any
-    const ChildC = {
-      inject: {
-        b: {
-          from: 'a'
+    })
+
+    const defineChild = (injectOptions: any, injectedKey = 'b') =>
+      ({
+        inject: injectOptions,
+        render() {
+          return this[injectedKey]
         }
-      },
-      render() {
-        return this.b
+      } as any)
+
+    const ChildA = defineChild(['a'], 'a')
+    const ChildB = defineChild({ b: 'a' })
+    const ChildC = defineChild({
+      b: {
+        from: 'a'
       }
-    } as any
-    const ChildD = {
-      inject: {
-        b: {
-          from: 'c',
-          default: 2
-        }
-      },
-      render() {
-        return this.b
+    })
+    const ChildD = defineChild({
+      b: {
+        from: 'c',
+        default: 2
       }
-    } as any
-
-    expect(renderToString(h(Root))).toBe(`1112`)
+    })
+    const ChildE = defineChild({
+      b: {
+        from: 'c',
+        default: () => 3
+      }
+    })
+    expect(renderToString(h(Root))).toBe(`11123`)
   })
 
   test('lifecycle', async () => {

+ 11 - 3
packages/runtime-core/src/apiInject.ts

@@ -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.`)
     }

+ 5 - 1
packages/runtime-core/src/componentOptions.ts

@@ -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)
         }