Преглед на файлове

fix(runtime-core): fix provide function data access in extends/mixins

fix #2300
Evan You преди 5 години
родител
ревизия
f06518a8c9
променени са 2 файла, в които са добавени 68 реда и са изтрити 11 реда
  1. 30 0
      packages/runtime-core/__tests__/apiOptions.spec.ts
  2. 38 11
      packages/runtime-core/src/componentOptions.ts

+ 30 - 0
packages/runtime-core/__tests__/apiOptions.spec.ts

@@ -324,6 +324,36 @@ describe('api: options', () => {
     expect(renderToString(h(Root))).toBe(`11112345`)
   })
 
+  test('provide accessing data in extends', () => {
+    const Base = defineComponent({
+      data() {
+        return {
+          a: 1
+        }
+      },
+      provide() {
+        return {
+          a: this.a
+        }
+      }
+    })
+
+    const Child = {
+      inject: ['a'],
+      render() {
+        return (this as any).a
+      }
+    }
+
+    const Root = defineComponent({
+      extends: Base,
+      render() {
+        return h(Child)
+      }
+    })
+    expect(renderToString(h(Root))).toBe(`1`)
+  })
+
   test('lifecycle', async () => {
     const count = ref(0)
     const root = nodeOps.createElement('div')

+ 38 - 11
packages/runtime-core/src/componentOptions.ts

@@ -430,6 +430,7 @@ export function applyOptions(
   options: ComponentOptions,
   deferredData: DataFn[] = [],
   deferredWatch: ComponentWatchOptions[] = [],
+  deferredProvide: (Data | Function)[] = [],
   asMixin: boolean = false
 ) {
   const {
@@ -483,16 +484,29 @@ export function applyOptions(
     )
     isInBeforeCreate = false
     // global mixins are applied first
-    applyMixins(instance, globalMixins, deferredData, deferredWatch)
+    applyMixins(
+      instance,
+      globalMixins,
+      deferredData,
+      deferredWatch,
+      deferredProvide
+    )
   }
 
   // extending a base component...
   if (extendsOptions) {
-    applyOptions(instance, extendsOptions, deferredData, deferredWatch, true)
+    applyOptions(
+      instance,
+      extendsOptions,
+      deferredData,
+      deferredWatch,
+      deferredProvide,
+      true
+    )
   }
   // local mixins
   if (mixins) {
-    applyMixins(instance, mixins, deferredData, deferredWatch)
+    applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide)
   }
 
   const checkDuplicateProperties = __DEV__ ? createDuplicateChecker() : null
@@ -634,12 +648,17 @@ export function applyOptions(
   }
 
   if (provideOptions) {
-    const provides = isFunction(provideOptions)
-      ? provideOptions.call(publicThis)
-      : provideOptions
-    for (const key in provides) {
-      provide(key, provides[key])
-    }
+    deferredProvide.push(provideOptions)
+  }
+  if (!asMixin && deferredProvide.length) {
+    deferredProvide.forEach(provideOptions => {
+      const provides = isFunction(provideOptions)
+        ? provideOptions.call(publicThis)
+        : provideOptions
+      for (const key in provides) {
+        provide(key, provides[key])
+      }
+    })
   }
 
   // asset options.
@@ -777,10 +796,18 @@ function applyMixins(
   instance: ComponentInternalInstance,
   mixins: ComponentOptions[],
   deferredData: DataFn[],
-  deferredWatch: ComponentWatchOptions[]
+  deferredWatch: ComponentWatchOptions[],
+  deferredProvide: (Data | Function)[]
 ) {
   for (let i = 0; i < mixins.length; i++) {
-    applyOptions(instance, mixins[i], deferredData, deferredWatch, true)
+    applyOptions(
+      instance,
+      mixins[i],
+      deferredData,
+      deferredWatch,
+      deferredProvide,
+      true
+    )
   }
 }