Skip to content

Commit 179b397

Browse files
committed
feat(effectScope): add lazy-initialized signal getter with automatic abort on stop
1 parent b555f02 commit 179b397

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

packages/reactivity/__tests__/effectScope.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,4 +362,21 @@ describe('reactivity/effect/scope', () => {
362362
expect(scope.effects.length).toBe(0)
363363
expect(scope.cleanups.length).toBe(0)
364364
})
365+
366+
test('signal', () => {
367+
const scope = effectScope()
368+
// should not create an `AbortController` until `scope.signal` is accessed
369+
expect((scope as any)._controller).toBeUndefined()
370+
371+
const { signal } = scope
372+
expect((scope as any)._controller).toBeDefined()
373+
expect(signal).toBeDefined()
374+
375+
const spy = vi.fn()
376+
signal.addEventListener('abort', spy)
377+
378+
scope.stop()
379+
// should trigger `abort` on the `signal` when `scope.stop()` is called.
380+
expect(spy).toBeCalled()
381+
})
365382
})

packages/reactivity/src/effectScope.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ export class EffectScope {
3939
* @internal
4040
*/
4141
private index: number | undefined
42+
/**
43+
* @internal
44+
*/
45+
private _controller: AbortController | undefined
46+
47+
get signal(): AbortSignal {
48+
if (!this._controller) this._controller = new AbortController()
49+
50+
return this._controller.signal
51+
}
4252

4353
constructor(public detached = false) {
4454
this.parent = activeEffectScope
@@ -129,6 +139,9 @@ export class EffectScope {
129139
stop(fromParent?: boolean): void {
130140
if (this._active) {
131141
this._active = false
142+
143+
if (this._controller) this._controller.abort()
144+
132145
let i, l
133146
for (i = 0, l = this.effects.length; i < l; i++) {
134147
this.effects[i].stop()

0 commit comments

Comments
 (0)