소스 검색

fix(runtime-core): use separate emits caches for components and mixins (#11661)

Red Huang 7 달 전
부모
커밋
15fc75f403
2개의 변경된 파일45개의 추가작업 그리고 1개의 파일을 삭제
  1. 42 0
      packages/runtime-core/__tests__/componentEmits.spec.ts
  2. 3 1
      packages/runtime-core/src/componentEmits.ts

+ 42 - 0
packages/runtime-core/__tests__/componentEmits.spec.ts

@@ -3,6 +3,7 @@
 
 import {
   type ComponentPublicInstance,
+  createApp,
   defineComponent,
   h,
   nextTick,
@@ -598,4 +599,45 @@ describe('component: emit', () => {
     render(h(ComponentC), el)
     expect(renderFn).toHaveBeenCalledTimes(1)
   })
+
+  test('merging emits for a component that is also used as a mixin', () => {
+    const render = () => h('div')
+    const CompA = {
+      render,
+    }
+    const validateByMixin = vi.fn(() => true)
+    const validateByGlobalMixin = vi.fn(() => true)
+
+    const mixin = {
+      emits: {
+        one: validateByMixin,
+      },
+    }
+
+    const CompB = defineComponent({
+      mixins: [mixin, CompA],
+      created(this) {
+        this.$emit('one', 1)
+      },
+      render,
+    })
+
+    const app = createApp({
+      render() {
+        return [h(CompA), h(CompB)]
+      },
+    })
+
+    app.mixin({
+      emits: {
+        one: validateByGlobalMixin,
+        two: null,
+      },
+    })
+
+    const root = nodeOps.createElement('div')
+    app.mount(root)
+    expect(validateByMixin).toHaveBeenCalledTimes(1)
+    expect(validateByGlobalMixin).not.toHaveBeenCalled()
+  })
 })

+ 3 - 1
packages/runtime-core/src/componentEmits.ts

@@ -232,12 +232,14 @@ export function emit(
   }
 }
 
+const mixinEmitsCache = new WeakMap<ConcreteComponent, ObjectEmitsOptions>()
 export function normalizeEmitsOptions(
   comp: ConcreteComponent,
   appContext: AppContext,
   asMixin = false,
 ): ObjectEmitsOptions | null {
-  const cache = appContext.emitsCache
+  const cache =
+    __FEATURE_OPTIONS_API__ && asMixin ? mixinEmitsCache : appContext.emitsCache
   const cached = cache.get(comp)
   if (cached !== undefined) {
     return cached