feat: add spawner utility

Introduce `createSpawner` and `spawnerEffect` to manage the lifecycle
of side effects based on a collection of IDs. `spawnerEffect` uses
Preact signals to automatically trigger spawners when IDs are added
to an iterable and cleanup functions when they are removed.
This commit is contained in:
hypercross 2026-04-23 10:20:13 +08:00
parent bbab3cc43b
commit e8c995f74f
2 changed files with 41 additions and 0 deletions

View File

@ -71,4 +71,6 @@ export { createRNG, Mulberry32RNG } from "./utils/rng";
export type { MiddlewareChain } from "./utils/middleware";
export { createMiddlewareChain } from "./utils/middleware";
export * from "./utils/spawner";
export * from "@preact/signals-core";

39
src/utils/spawner.ts Normal file
View File

@ -0,0 +1,39 @@
import { effect } from "@preact/signals-core";
export type SpawnerFunction = (id: string) => () => void;
export function createSpawner(spawner: SpawnerFunction) {
const entries = new Map<string, () => void>();
function update(set: Set<string>) {
for (const key of set) {
if (!entries.has(key)) {
entries.set(key, spawner(key));
}
}
for (const [key, entry] of entries) {
if (!set.has(key)) {
entry();
entries.delete(key);
}
}
}
return update;
}
export function spawnerEffect(
iterable: () => Iterable<string>,
spawner: SpawnerFunction,
) {
const update = createSpawner(spawner);
return effect(() => {
const set = new Set<string>();
for (const each of iterable()) {
set.add(each);
}
update(set);
});
}