fix(watch): post flush watchers should not fire when component is unmounted
fix #1603
This commit is contained in:
@@ -234,33 +234,39 @@ function doWatch(
|
||||
}
|
||||
|
||||
let oldValue = isArray(source) ? [] : INITIAL_WATCHER_VALUE
|
||||
const applyCb = cb
|
||||
? () => {
|
||||
if (instance && instance.isUnmounted) {
|
||||
return
|
||||
}
|
||||
const newValue = runner()
|
||||
if (deep || hasChanged(newValue, oldValue)) {
|
||||
// cleanup before running cb again
|
||||
if (cleanup) {
|
||||
cleanup()
|
||||
}
|
||||
callWithAsyncErrorHandling(cb, instance, ErrorCodes.WATCH_CALLBACK, [
|
||||
newValue,
|
||||
// pass undefined as the old value when it's changed for the first time
|
||||
oldValue === INITIAL_WATCHER_VALUE ? undefined : oldValue,
|
||||
onInvalidate
|
||||
])
|
||||
oldValue = newValue
|
||||
const job = () => {
|
||||
if (!runner.active) {
|
||||
return
|
||||
}
|
||||
if (cb) {
|
||||
// watch(source, cb)
|
||||
const newValue = runner()
|
||||
if (deep || hasChanged(newValue, oldValue)) {
|
||||
// cleanup before running cb again
|
||||
if (cleanup) {
|
||||
cleanup()
|
||||
}
|
||||
callWithAsyncErrorHandling(cb, instance, ErrorCodes.WATCH_CALLBACK, [
|
||||
newValue,
|
||||
// pass undefined as the old value when it's changed for the first time
|
||||
oldValue === INITIAL_WATCHER_VALUE ? undefined : oldValue,
|
||||
onInvalidate
|
||||
])
|
||||
oldValue = newValue
|
||||
}
|
||||
: void 0
|
||||
} else {
|
||||
// watchEffect
|
||||
runner()
|
||||
}
|
||||
}
|
||||
|
||||
let scheduler: (job: () => any) => void
|
||||
if (flush === 'sync') {
|
||||
scheduler = invoke
|
||||
} else if (flush === 'pre') {
|
||||
scheduler = job => {
|
||||
// ensure it's queued before component updates (which have positive ids)
|
||||
job.id = -1
|
||||
scheduler = () => {
|
||||
if (!instance || instance.isMounted) {
|
||||
queueJob(job)
|
||||
} else {
|
||||
@@ -270,22 +276,22 @@ function doWatch(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
scheduler = job => queuePostRenderEffect(job, instance && instance.suspense)
|
||||
scheduler = () => queuePostRenderEffect(job, instance && instance.suspense)
|
||||
}
|
||||
|
||||
const runner = effect(getter, {
|
||||
lazy: true,
|
||||
onTrack,
|
||||
onTrigger,
|
||||
scheduler: applyCb ? () => scheduler(applyCb) : scheduler
|
||||
scheduler
|
||||
})
|
||||
|
||||
recordInstanceBoundEffect(runner)
|
||||
|
||||
// initial run
|
||||
if (applyCb) {
|
||||
if (cb) {
|
||||
if (immediate) {
|
||||
applyCb()
|
||||
job()
|
||||
} else {
|
||||
oldValue = runner()
|
||||
}
|
||||
|
||||
@@ -2025,19 +2025,17 @@ 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)
|
||||
|
||||
Reference in New Issue
Block a user