From 58b07069ad33c8a8e44cb47b81084a452dda2846 Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 6 Jul 2020 21:50:56 -0400 Subject: [PATCH] fix(watch): stop instance-bound watchers in post render queue so that changes triggered in beforeUnmount get correct value in callback fix #1525 --- packages/runtime-core/src/apiWatch.ts | 10 +++------- packages/runtime-core/src/renderer.ts | 12 +++++++----- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index 4d98d425..bca2fbef 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -29,7 +29,6 @@ import { callWithErrorHandling, callWithAsyncErrorHandling } from './errorHandling' -import { onBeforeUnmount } from './apiLifecycle' import { queuePostRenderEffect } from './renderer' import { warn } from './warning' @@ -134,7 +133,8 @@ export function watch( function doWatch( source: WatchSource | WatchSource[] | WatchEffect, cb: WatchCallback | null, - { immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ + { immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ, + instance = currentInstance ): WatchStopHandle { if (__DEV__ && !cb) { if (immediate !== undefined) { @@ -160,8 +160,6 @@ function doWatch( ) } - const instance = currentInstance - let getter: () => any if (isArray(source)) { getter = () => @@ -316,9 +314,7 @@ export function instanceWatch( const getter = isString(source) ? () => publicThis[source] : source.bind(publicThis) - const stop = watch(getter, cb.bind(publicThis), options) - onBeforeUnmount(stop, this) - return stop + return doWatch(getter, cb.bind(publicThis), options, this) } function traverse(value: unknown, seen: Set = new Set()) { diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 2c827136..0b3bd831 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1996,17 +1996,19 @@ function baseCreateRenderer( if (bum) { invokeArrayFns(bum) } - if (effects) { - for (let i = 0; i < effects.length; i++) { - stop(effects[i]) - } - } // update may be null if a component is unmounted before its async // setup has resolved. if (update) { stop(update) unmount(subTree, instance, parentSuspense, doRemove) } + if (effects) { + queuePostRenderEffect(() => { + for (let i = 0; i < effects.length; i++) { + stop(effects[i]) + } + }, parentSuspense) + } // unmounted hook if (um) { queuePostRenderEffect(um, parentSuspense)