Skip to content

Commit 3656408

Browse files
committed
fix: strict effect scope hierarchy
1 parent 51dfbf9 commit 3656408

File tree

2 files changed

+28
-23
lines changed

2 files changed

+28
-23
lines changed

src/index.ts

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ export let batchDepth = 0;
6161
let notifyIndex = 0;
6262
let queuedEffectsLength = 0;
6363
let activeSub: ReactiveNode | undefined;
64-
let activeScope: EffectScope | undefined;
6564

6665
export function getCurrentSub(): ReactiveNode | undefined {
6766
return activeSub;
@@ -73,16 +72,6 @@ export function setCurrentSub(sub: ReactiveNode | undefined) {
7372
return prevSub;
7473
}
7574

76-
export function getCurrentScope(): EffectScope | undefined {
77-
return activeScope;
78-
}
79-
80-
export function setCurrentScope(scope: EffectScope | undefined) {
81-
const prevScope = activeScope;
82-
activeScope = scope;
83-
return prevScope;
84-
}
85-
8675
export function startBatch() {
8776
++batchDepth;
8877
}
@@ -151,8 +140,6 @@ export function effect(fn: () => void): () => void {
151140
};
152141
if (activeSub !== undefined) {
153142
link(e, activeSub);
154-
} else if (activeScope !== undefined) {
155-
link(e, activeScope);
156143
}
157144
const prev = setCurrentSub(e);
158145
try {
@@ -171,16 +158,14 @@ export function effectScope(fn: () => void): () => void {
171158
subsTail: undefined,
172159
flags: 0 satisfies ReactiveFlags.None,
173160
};
174-
if (activeScope !== undefined) {
175-
link(e, activeScope);
161+
if (activeSub !== undefined) {
162+
link(e, activeSub);
176163
}
177-
const prevSub = setCurrentSub(undefined);
178-
const prevScope = setCurrentScope(e);
164+
const prev = setCurrentSub(e);
179165
try {
180166
fn();
181167
} finally {
182-
setCurrentScope(prevScope);
183-
setCurrentSub(prevSub);
168+
setCurrentSub(prev);
184169
}
185170
return effectOper.bind(e);
186171
}
@@ -270,8 +255,6 @@ function computedOper<T>(this: Computed<T>): T {
270255
}
271256
if (activeSub !== undefined) {
272257
link(this, activeSub);
273-
} else if (activeScope !== undefined) {
274-
link(this, activeScope);
275258
}
276259
return this.value!;
277260
}
@@ -298,8 +281,13 @@ function signalOper<T>(this: Signal<T>, ...value: [T]): T | void {
298281
}
299282
}
300283
}
301-
if (activeSub !== undefined) {
302-
link(this, activeSub);
284+
let sub = activeSub;
285+
while (sub !== undefined) {
286+
if (sub.flags & 3 as ReactiveFlags.Mutable | ReactiveFlags.Watching) {
287+
link(this, sub);
288+
break;
289+
}
290+
sub = sub.subs?.sub;
303291
}
304292
return value;
305293
}

tests/effectScope.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,20 @@ test('should dispose inner effects if created in an effect', () => {
4646
expect(triggers).toBe(2);
4747
});
4848
});
49+
50+
test('should track signal updates in an inner scope when accessed by an outer effect', () => {
51+
const source = signal(1);
52+
53+
let triggers = 0;
54+
55+
effect(() => {
56+
effectScope(() => {
57+
source();
58+
});
59+
triggers++;
60+
});
61+
62+
expect(triggers).toBe(1);
63+
source(2);
64+
expect(triggers).toBe(2);
65+
});

0 commit comments

Comments
 (0)