Skip to content

Commit

Permalink
Allow for nested effect() calls (#4)
Browse files Browse the repository at this point in the history
* Red

* Green

* Refactor
  • Loading branch information
amatiasq authored Nov 13, 2023
1 parent 817f0c5 commit 8d63c2c
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 11 deletions.
38 changes: 37 additions & 1 deletion src/utils/signals/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,41 @@ describe("signals", () => {

it.todo("should log an alert in DEV when using nested effects", () => { });

it.todo('should work without race conditions between async effects and signals')
it('should work with async effects', async () => {
const { state, effect } = signals();
const count = state(0);
const delay = Promise.resolve();
let lastSeen = -1;

effect(async () => {
await delay;
lastSeen = count.value;
});

await delay;
expect(lastSeen).toBe(0);
count.value = 1;
await delay;
expect(lastSeen).toBe(1);
});

it('should work without race conditions between async effects and signals', async () => {
const { state, effect } = signals();
const count = state(0);
const delay = Promise.resolve();
let lastSeen = -1;

effect(async () => {
await delay;
lastSeen = count.value;
});

effect(() => {});

await delay;
expect(lastSeen).toBe(0);
count.value = 1;
await delay;
expect(lastSeen).toBe(1);
});
});
24 changes: 14 additions & 10 deletions src/utils/signals/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
type Effect = () => void | Promise<void>;
type Cleanup = Effect;
type Current = Effect | 0 | undefined;

export default function signals() {
let cleanups = new Map<Current, Cleanup[]>();
let current: Current;
const stack: Effect[] = [];
let cleanups = new Map<Effect, Cleanup[]>();

return {
cleanAll() {
Expand All @@ -17,7 +16,7 @@ export default function signals() {
const effects = new Set<Effect>();
return {
get value() {
if (current) effects.add(current);
if (stack[0]) effects.add(stack[0]);
return initialValue;
},
set value(v) {
Expand All @@ -31,16 +30,21 @@ export default function signals() {
},
};
},
effect(fn: Effect) {
current = fn;
async effect(fn: Effect) {
stack.unshift(fn);
const p = fn();
if (p?.then) p.then(() => (current = 0));
else current = 0;
if (p?.then) await p;
removeFromStack(fn);
},
cleanup(fn: Cleanup) {
const cleans = cleanups.get(current) ?? [];
const cleans = cleanups.get(stack[0]) ?? [];
cleans.push(fn);
cleanups.set(current, cleans);
cleanups.set(stack[0], cleans);
},
};

function removeFromStack(fn: Effect) {
const index = stack.lastIndexOf(fn);
if (index !== -1) stack.splice(index, 1);
}
}

0 comments on commit 8d63c2c

Please sign in to comment.