@@ -30,13 +30,18 @@ export function toObserver<T>(
3030export type WatchedEffect = ( ) => ( ( ) => void ) | void | undefined
3131
3232interface WatchableNode extends ReactiveNode {
33+ /**
34+ * Reference count: number of direct subs that are alive
35+ * When >0, the node is "alive" and its watch effects should be running
36+ * When =0, the node is "dead", and its watch effects should be stopped
37+ */
3338 _watches ?: number
3439 _watchEffects ?: Array < WatchedEffect >
3540 _watchCleanups ?: Array < ( ( ) => void ) | void | undefined >
3641}
3742
38- function getWatchCount ( node : WatchableNode ) : number {
39- return node . _watches || ( node . flags & ReactiveFlags . Watching ) ? 1 : 0
43+ function isWatched ( node : WatchableNode ) : boolean {
44+ return ! ! node . _watches
4045}
4146
4247function addWatch ( node : WatchableNode ) {
@@ -54,7 +59,7 @@ function addWatch(node: WatchableNode) {
5459 deps = deps . nextDep
5560 }
5661
57- // 2. start/run watch effects
62+ // 2. start/run own watch effects
5863 const watchEffects = node . _watchEffects
5964 if ( watchEffects ?. length ) {
6065 node . _watchCleanups = watchEffects . map ( ( ef ) => ef ( ) )
@@ -82,7 +87,11 @@ function removeWatch(node: WatchableNode) {
8287 }
8388}
8489
85- export function whileWatched ( node : WatchableNode , fn : WatchedEffect ) {
90+ /**
91+ * Causes `fn` to be called when `node` becomes gains its first live subscriber.
92+ * If `fn` returns a cleanup function, it will be called when `node` loses its last live subscriber.
93+ */
94+ export function whiteWatched ( node : WatchableNode , fn : WatchedEffect ) {
8695 const initialEffects = ( node . _watchEffects ??= [ ] )
8796 initialEffects . push ( fn )
8897 if ( node . _watches ) {
@@ -157,14 +166,6 @@ const { link: _link, unlink: _unlink, propagate, checkDirty, shallowPropagate }
157166 effect . flags &= ~ ReactiveFlags . Watching
158167 } ,
159168 unwatched ( atom : InternalAtom < any > ) : void {
160- atom . _watched = false
161- // not sure if this should go above or below the deps purge
162- // preorder vs postorder
163- if ( atom . _watchedCleanups ?. length ) {
164- atom . _watchedCleanups . forEach ( ( cleanup ) => cleanup ?.( ) )
165- atom . _watchedCleanups . length = 0
166- }
167-
168169 if ( atom . depsTail !== undefined ) {
169170 atom . depsTail = undefined
170171 atom . flags = ReactiveFlags . Mutable | ReactiveFlags . Dirty
@@ -178,7 +179,7 @@ function link(dep: ReactiveNode, sub: ReactiveNode, version: number) {
178179 _link ( dep , sub , version )
179180 const newTail = dep . subsTail
180181
181- if ( newTail && newTail !== originalTail && getWatchCount ( sub ) ) {
182+ if ( newTail && newTail !== originalTail && isWatched ( sub ) ) {
182183 // Propagate watch liveness from sub -> dep
183184 addWatch ( dep )
184185 }
@@ -191,7 +192,7 @@ function unlink(
191192 sub : ReactiveNode = link . sub
192193) : Link | undefined {
193194 const dep = link . dep
194- if ( getWatchCount ( sub ) ) {
195+ if ( isWatched ( sub ) ) {
195196 // Revoke liveness from this sub on dep when unlinked
196197 removeWatch ( dep )
197198 }
@@ -374,21 +375,7 @@ export function createAtom<T>(
374375 } ,
375376
376377 whileWatched ( listener : WatchedEffect ) : ( ) => void {
377- atom . _watchedSubs ??= [ ]
378- atom . _watchedSubs . push ( listener )
379- if ( atom . _watched ) {
380- atom . _watchedCleanups ??= [ ]
381- atom . _watchedCleanups . push ( listener ( ) )
382- }
383- return ( ) => {
384- if ( ! atom . _watchedSubs ) {
385- return
386- }
387- const index = atom . _watchedSubs . indexOf ( listener )
388- if ( index !== - 1 ) {
389- atom . _watchedSubs . splice ( index , 1 )
390- }
391- }
378+ return whiteWatched ( this , listener )
392379 } ,
393380
394381 _update ( getValue ?: T | ( ( snapshot : T ) => T ) ) : boolean {
@@ -471,6 +458,7 @@ export function createAtom<T>(
471458}
472459
473460interface Effect extends ReactiveNode {
461+ _watches : number
474462 notify : ( ) => void
475463 stop : ( ) => void
476464}
@@ -496,6 +484,8 @@ function effect<T>(fn: () => T): Effect {
496484 subs : undefined ,
497485 subsTail : undefined ,
498486 flags : ReactiveFlags . Watching | ReactiveFlags . RecursedCheck ,
487+ // Effects are the source of liveness - they are created alive
488+ _watches : 1 ,
499489
500490 notify ( ) : void {
501491 const flags = this . flags
0 commit comments