Skip to content

Commit 69af377

Browse files
committed
fix: prevent effect recursion on first run
close #90
1 parent 4407e8c commit 69af377

File tree

3 files changed

+26
-3
lines changed

3 files changed

+26
-3
lines changed

src/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export function effect(fn: () => void): () => void {
147147
subsTail: undefined,
148148
deps: undefined,
149149
depsTail: undefined,
150-
flags: ReactiveFlags.Watching,
150+
flags: ReactiveFlags.Watching | ReactiveFlags.RecursedCheck,
151151
};
152152
const prevSub = setActiveSub(e);
153153
if (prevSub !== undefined) {
@@ -157,6 +157,7 @@ export function effect(fn: () => void): () => void {
157157
e.fn();
158158
} finally {
159159
activeSub = prevSub;
160+
e.flags &= ~ReactiveFlags.RecursedCheck;
160161
}
161162
return effectOper.bind(e);
162163
}
@@ -255,12 +256,13 @@ function computedOper<T>(this: Computed<T>): T {
255256
}
256257
}
257258
} else if (!flags) {
258-
this.flags = ReactiveFlags.Mutable;
259+
this.flags = ReactiveFlags.Mutable | ReactiveFlags.RecursedCheck;
259260
const prevSub = setActiveSub(this);
260261
try {
261262
this.value = this.getter();
262263
} finally {
263264
activeSub = prevSub;
265+
this.flags &= ~ReactiveFlags.RecursedCheck;
264266
}
265267
}
266268
const sub = activeSub;

src/system.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ export function createReactiveSystem({
250250
const flags = sub.flags;
251251
if ((flags & (ReactiveFlags.Pending | ReactiveFlags.Dirty)) === ReactiveFlags.Pending) {
252252
sub.flags = flags | ReactiveFlags.Dirty;
253-
if (flags & ReactiveFlags.Watching) {
253+
if ((flags & (ReactiveFlags.Watching | ReactiveFlags.RecursedCheck)) === ReactiveFlags.Watching) {
254254
notify(sub);
255255
}
256256
}

tests/effect.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,24 @@ test('should handle flags are indirectly updated during checkDirty', () => {
250250
a(true);
251251
expect(triggers).toBe(2);
252252
});
253+
254+
test('should handle effect recursion for the first execution', () => {
255+
const src1 = signal(0);
256+
const src2 = signal(0);
257+
258+
let triggers1 = 0;
259+
let triggers2 = 0;
260+
261+
effect(() => {
262+
triggers1++;
263+
src1(Math.min(src1() + 1, 5));
264+
});
265+
effect(() => {
266+
triggers2++;
267+
src2(Math.min(src2() + 1, 5));
268+
src2();
269+
});
270+
271+
expect(triggers1).toBe(1);
272+
expect(triggers2).toBe(1);
273+
});

0 commit comments

Comments
 (0)