Skip to content

Commit

Permalink
fix(reactivity): fix ref tracking of self-stopping effects
Browse files Browse the repository at this point in the history
close #5707
  • Loading branch information
yyx990803 committed Apr 13, 2022
1 parent f4f5e80 commit 154233a
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 1 deletion.
21 changes: 21 additions & 0 deletions packages/reactivity/__tests__/effect.spec.ts
@@ -1,4 +1,5 @@
import {
ref,
reactive,
effect,
stop,
Expand Down Expand Up @@ -801,6 +802,26 @@ describe('reactivity/effect', () => {
expect(dummy).toBe(3)
})

// #5707
// when an effect completes its run, it should clear the tracking bits of
// its tracked deps. However, if the effect stops itself, the deps list is
// emptied so their bits are never cleared.
it('edge case: self-stopping effect tracking ref', () => {
const c = ref(true)
const runner = effect(() => {
// reference ref
if (!c.value) {
// stop itself while running
stop(runner)
}
})
// trigger run
c.value = !c.value
// should clear bits
expect((c as any).dep.w).toBe(0)
expect((c as any).dep.n).toBe(0)
})

it('events: onStop', () => {
const onStop = jest.fn()
const runner = effect(() => {}, {
Expand Down
13 changes: 12 additions & 1 deletion packages/reactivity/src/effect.ts
Expand Up @@ -64,6 +64,10 @@ export class ReactiveEffect<T = any> {
* @internal
*/
allowRecurse?: boolean
/**
* @internal
*/
private deferStop?: boolean

onStop?: () => void
// dev only
Expand Down Expand Up @@ -114,11 +118,18 @@ export class ReactiveEffect<T = any> {
activeEffect = this.parent
shouldTrack = lastShouldTrack
this.parent = undefined

if (this.deferStop) {
this.stop()
}
}
}

stop() {
if (this.active) {
// stopped while running itself - defer the cleanup
if (activeEffect === this) {
this.deferStop = true
} else if (this.active) {
cleanupEffect(this)
if (this.onStop) {
this.onStop()
Expand Down

0 comments on commit 154233a

Please sign in to comment.