@@ -3,12 +3,15 @@ import type { TrackOpTypes, TriggerOpTypes } from './constants'
3
3
import { setupOnTrigger } from './debug'
4
4
import { activeEffectScope } from './effectScope'
5
5
import {
6
+ type Dependency ,
6
7
type Link ,
7
8
type Subscriber ,
8
9
SubscriberFlags ,
9
10
checkDirty ,
11
+ cleanup ,
10
12
endTracking ,
11
13
link ,
14
+ onCleanup ,
12
15
startTracking ,
13
16
unlink ,
14
17
} from './system'
@@ -36,6 +39,9 @@ export interface DebuggerOptions {
36
39
37
40
export interface ReactiveEffectOptions extends DebuggerOptions {
38
41
scheduler ?: EffectScheduler
42
+ /**
43
+ * @deprecated
44
+ */
39
45
onStop ?: ( ) => void
40
46
}
41
47
@@ -51,26 +57,24 @@ export enum EffectFlags {
51
57
ALLOW_RECURSE = 1 << 7 ,
52
58
PAUSED = 1 << 8 ,
53
59
NOTIFIED = 1 << 9 ,
54
- STOP = 1 << 10 ,
55
60
}
56
61
57
- export class ReactiveEffect < T = any > implements ReactiveEffectOptions {
62
+ export class ReactiveEffect < T = any >
63
+ implements ReactiveEffectOptions , Dependency , Subscriber
64
+ {
58
65
// Subscriber
59
66
deps : Link | undefined = undefined
60
67
depsTail : Link | undefined = undefined
61
68
flags : number = 0
69
+ cleanups : number = 0
62
70
63
71
// Dependency
64
72
subs : Link | undefined = undefined
65
73
subsTail : Link | undefined = undefined
66
74
67
- /**
68
- * @internal
69
- */
70
- cleanup ?: ( ) => void = undefined
71
-
72
- onStop ?: ( ) => void
75
+ // dev only
73
76
onTrack ?: ( event : DebuggerEvent ) => void
77
+ // dev only
74
78
onTrigger ?: ( event : DebuggerEvent ) => void
75
79
76
80
// @ts -expect-error
@@ -80,13 +84,13 @@ export class ReactiveEffect<T = any> implements ReactiveEffectOptions {
80
84
if ( fn !== undefined ) {
81
85
this . fn = fn
82
86
}
83
- if ( activeEffectScope && activeEffectScope . active ) {
87
+ if ( activeEffectScope ) {
84
88
link ( this , activeEffectScope )
85
89
}
86
90
}
87
91
88
92
get active ( ) : boolean {
89
- return ! ( this . flags & EffectFlags . STOP )
93
+ return this . deps !== undefined
90
94
}
91
95
92
96
pause ( ) : void {
@@ -122,12 +126,10 @@ export class ReactiveEffect<T = any> implements ReactiveEffectOptions {
122
126
}
123
127
124
128
run ( ) : T {
125
- let flags = this . flags
126
- if ( flags & EffectFlags . STOP ) {
127
- // stopped during cleanup
128
- return this . fn ( )
129
+ const cleanups = this . cleanups
130
+ if ( cleanups ) {
131
+ cleanup ( this , cleanups )
129
132
}
130
- cleanupEffect ( this )
131
133
const prevSub = activeSub
132
134
setActiveSub ( this )
133
135
startTracking ( this )
@@ -143,7 +145,7 @@ export class ReactiveEffect<T = any> implements ReactiveEffectOptions {
143
145
}
144
146
setActiveSub ( prevSub )
145
147
endTracking ( this )
146
- flags = this . flags
148
+ const flags = this . flags
147
149
if (
148
150
( flags & ( SubscriberFlags . Recursed | EffectFlags . ALLOW_RECURSE ) ) ===
149
151
( SubscriberFlags . Recursed | EffectFlags . ALLOW_RECURSE )
@@ -155,17 +157,15 @@ export class ReactiveEffect<T = any> implements ReactiveEffectOptions {
155
157
}
156
158
157
159
stop ( ) : void {
158
- const flags = this . flags
159
- if ( ! ( flags & EffectFlags . STOP ) ) {
160
- this . flags = flags | EffectFlags . STOP
161
- startTracking ( this )
162
- endTracking ( this )
163
- cleanupEffect ( this )
164
- this . onStop && this . onStop ( )
165
-
166
- if ( this . subs !== undefined ) {
167
- unlink ( this . subs )
168
- }
160
+ const sub = this . subs
161
+ const cleanups = this . cleanups
162
+ if ( sub !== undefined ) {
163
+ unlink ( sub )
164
+ }
165
+ startTracking ( this )
166
+ endTracking ( this )
167
+ if ( cleanups ) {
168
+ cleanup ( this , cleanups )
169
169
}
170
170
}
171
171
@@ -202,6 +202,15 @@ export function effect<T = any>(
202
202
203
203
const e = new ReactiveEffect ( fn )
204
204
if ( options ) {
205
+ const onStop = options . onStop
206
+ if ( onStop ) {
207
+ delete options . onStop
208
+ const stop = e . stop . bind ( e )
209
+ e . stop = ( ) => {
210
+ stop ( )
211
+ onStop ( )
212
+ }
213
+ }
205
214
extend ( e , options )
206
215
}
207
216
try {
@@ -286,8 +295,9 @@ export function resetTracking(): void {
286
295
* an active effect.
287
296
*/
288
297
export function onEffectCleanup ( fn : ( ) => void , failSilently = false ) : void {
289
- if ( activeSub instanceof ReactiveEffect ) {
290
- activeSub . cleanup = fn
298
+ const e = activeSub
299
+ if ( e instanceof ReactiveEffect ) {
300
+ onCleanup ( e , ( ) => cleanupEffect ( e , fn ) )
291
301
} else if ( __DEV__ && ! failSilently ) {
292
302
warn (
293
303
`onEffectCleanup() was called when there was no active effect` +
@@ -296,18 +306,14 @@ export function onEffectCleanup(fn: () => void, failSilently = false): void {
296
306
}
297
307
}
298
308
299
- function cleanupEffect ( e : ReactiveEffect ) {
300
- const cleanup = e . cleanup
301
- if ( cleanup !== undefined ) {
302
- e . cleanup = undefined
303
- // run cleanup without active effect
304
- const prevSub = activeSub
305
- activeSub = undefined
306
- try {
307
- cleanup ( )
308
- } finally {
309
- activeSub = prevSub
310
- }
309
+ function cleanupEffect ( e : ReactiveEffect , fn : ( ) => void ) {
310
+ // run cleanup without active effect
311
+ const prevSub = activeSub
312
+ activeSub = undefined
313
+ try {
314
+ fn ( )
315
+ } finally {
316
+ activeSub = prevSub
311
317
}
312
318
}
313
319
0 commit comments