Skip to content

Commit 124c385

Browse files
committedSep 14, 2020
perf: should not trigger child update if changed prop is declared emit listener
close #2072
1 parent 4de5b11 commit 124c385

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed
 

‎packages/runtime-core/__tests__/rendererComponent.spec.ts

+23
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,27 @@ describe('renderer: component', () => {
8181
render(h(Comp2), root)
8282
expect(serializeInner(root)).toBe('<span>foo</span>')
8383
})
84+
85+
// #2072
86+
it('should not update Component if only changed props are declared emit listeners', () => {
87+
const Comp1 = {
88+
emits: ['foo'],
89+
updated: jest.fn(),
90+
render: () => null
91+
}
92+
const root = nodeOps.createElement('div')
93+
render(
94+
h(Comp1, {
95+
onFoo: () => {}
96+
}),
97+
root
98+
)
99+
render(
100+
h(Comp1, {
101+
onFoo: () => {}
102+
}),
103+
root
104+
)
105+
expect(Comp1.updated).not.toHaveBeenCalled()
106+
})
84107
})

‎packages/runtime-core/src/componentRenderUtils.ts

+18-6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { PatchFlags, ShapeFlags, isOn, isModelListener } from '@vue/shared'
1818
import { warn } from './warning'
1919
import { isHmrUpdating } from './hmr'
2020
import { NormalizedProps } from './componentProps'
21+
import { isEmitListener } from './componentEmits'
2122

2223
// mark the current rendering instance for asset resolution (e.g.
2324
// resolveComponent, resolveDirective) during render
@@ -290,8 +291,9 @@ export function shouldUpdateComponent(
290291
nextVNode: VNode,
291292
optimized?: boolean
292293
): boolean {
293-
const { props: prevProps, children: prevChildren } = prevVNode
294+
const { props: prevProps, children: prevChildren, component } = prevVNode
294295
const { props: nextProps, children: nextChildren, patchFlag } = nextVNode
296+
const emits = component!.emitsOptions
295297

296298
// Parent component's render function was hot-updated. Since this may have
297299
// caused the child component's slots content to have changed, we need to
@@ -316,12 +318,15 @@ export function shouldUpdateComponent(
316318
return !!nextProps
317319
}
318320
// presence of this flag indicates props are always non-null
319-
return hasPropsChanged(prevProps, nextProps!)
321+
return hasPropsChanged(prevProps, nextProps!, emits)
320322
} else if (patchFlag & PatchFlags.PROPS) {
321323
const dynamicProps = nextVNode.dynamicProps!
322324
for (let i = 0; i < dynamicProps.length; i++) {
323325
const key = dynamicProps[i]
324-
if (nextProps![key] !== prevProps![key]) {
326+
if (
327+
nextProps![key] !== prevProps![key] &&
328+
!isEmitListener(emits, key)
329+
) {
325330
return true
326331
}
327332
}
@@ -343,20 +348,27 @@ export function shouldUpdateComponent(
343348
if (!nextProps) {
344349
return true
345350
}
346-
return hasPropsChanged(prevProps, nextProps)
351+
return hasPropsChanged(prevProps, nextProps, emits)
347352
}
348353

349354
return false
350355
}
351356

352-
function hasPropsChanged(prevProps: Data, nextProps: Data): boolean {
357+
function hasPropsChanged(
358+
prevProps: Data,
359+
nextProps: Data,
360+
emitsOptions: ComponentInternalInstance['emitsOptions']
361+
): boolean {
353362
const nextKeys = Object.keys(nextProps)
354363
if (nextKeys.length !== Object.keys(prevProps).length) {
355364
return true
356365
}
357366
for (let i = 0; i < nextKeys.length; i++) {
358367
const key = nextKeys[i]
359-
if (nextProps[key] !== prevProps[key]) {
368+
if (
369+
nextProps[key] !== prevProps[key] &&
370+
!isEmitListener(emitsOptions, key)
371+
) {
360372
return true
361373
}
362374
}

0 commit comments

Comments
 (0)