From d5824b97c570eb9e3d689b840f098e401e458d05 Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 26 Mar 2021 15:52:45 -0400 Subject: [PATCH] fix(runtime-core): should not track deps in pre flush watcher callbacks fix #2728 --- .../runtime-core/__tests__/apiWatch.spec.ts | 38 +++++++++++++++++++ packages/runtime-core/src/renderer.ts | 11 +++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/__tests__/apiWatch.spec.ts b/packages/runtime-core/__tests__/apiWatch.spec.ts index 30248072..4a0b7a90 100644 --- a/packages/runtime-core/__tests__/apiWatch.spec.ts +++ b/packages/runtime-core/__tests__/apiWatch.spec.ts @@ -877,4 +877,42 @@ describe('api: watch', () => { expect(instance).toBeDefined() expect(source).toHaveBeenCalledWith(instance) }) + + // #2728 + test('pre watcher callbacks should not track dependencies', async () => { + const a = ref(0) + const b = ref(0) + const updated = jest.fn() + + const Child = defineComponent({ + props: ['a'], + updated, + watch: { + a() { + b.value + } + }, + render() { + return h('div', this.a) + } + }) + + const Parent = defineComponent({ + render() { + return h(Child, { a: a.value }) + } + }) + + const root = nodeOps.createElement('div') + createApp(Parent).mount(root) + + a.value++ + await nextTick() + expect(updated).toHaveBeenCalledTimes(1) + + b.value++ + await nextTick() + // should not track b as dependency of Child + expect(updated).toHaveBeenCalledTimes(1) + }) }) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 4f67869b..4375dcdb 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -48,7 +48,14 @@ import { flushPreFlushCbs, SchedulerCb } from './scheduler' -import { effect, stop, ReactiveEffectOptions, isRef } from '@vue/reactivity' +import { + effect, + stop, + ReactiveEffectOptions, + isRef, + pauseTracking, + resetTracking +} from '@vue/reactivity' import { updateProps } from './componentProps' import { updateSlots } from './componentSlots' import { pushWarningContext, popWarningContext, warn } from './warning' @@ -1567,9 +1574,11 @@ function baseCreateRenderer( updateProps(instance, nextVNode.props, prevProps, optimized) updateSlots(instance, nextVNode.children) + pauseTracking() // props update may have triggered pre-flush watchers. // flush them before the render update. flushPreFlushCbs(undefined, instance.update) + resetTracking() } const patchChildren: PatchChildrenFn = (