fix(runtime-core): ensure tracking is paused when emit() calls handler so it can safely be called in effects

fix: #6669
This commit is contained in:
Thorsten Luenborg 2022-09-17 11:51:35 +02:00
parent 8772a01a92
commit 1c02e5a9c2
2 changed files with 38 additions and 1 deletions

View File

@ -7,7 +7,9 @@ import {
h, h,
nodeOps, nodeOps,
toHandlers, toHandlers,
nextTick nextTick,
ref,
watchEffect
} from '@vue/runtime-test' } from '@vue/runtime-test'
import { isEmitListener } from '../src/componentEmits' import { isEmitListener } from '../src/componentEmits'
@ -431,4 +433,36 @@ describe('component: emit', () => {
await nextTick() await nextTick()
expect(fn).not.toHaveBeenCalled() expect(fn).not.toHaveBeenCalled()
}) })
test('should not track during listener execution', async () => {
const counter = ref(0)
const Comp = defineComponent({
emits: ['interaction'],
setup(props, { emit }) {
const doEmit = ref(true)
watchEffect(() => {
if (doEmit.value) emit('interaction')
})
return () => h('div')
}
})
const el = nodeOps.createElement('div')
render(
h(Comp, {
onInteraction: async () => {
if (counter.value < 5) {
await nextTick()
counter.value++
}
}
}),
el
)
await nextTick()
await nextTick()
await nextTick()
expect(counter.value).toBe(1)
})
}) })

View File

@ -27,6 +27,7 @@ import {
compatModelEventPrefix, compatModelEventPrefix,
compatModelEmit compatModelEmit
} from './compat/componentVModel' } from './compat/componentVModel'
import { pauseTracking, resetTracking } from '@vue/reactivity'
export type ObjectEmitsOptions = Record< export type ObjectEmitsOptions = Record<
string, string,
@ -161,12 +162,14 @@ export function emit(
} }
if (handler) { if (handler) {
pauseTracking()
callWithAsyncErrorHandling( callWithAsyncErrorHandling(
handler, handler,
instance, instance,
ErrorCodes.COMPONENT_EVENT_HANDLER, ErrorCodes.COMPONENT_EVENT_HANDLER,
args args
) )
resetTracking()
} }
const onceHandler = props[handlerName + `Once`] const onceHandler = props[handlerName + `Once`]