diff --git a/src/index.ts b/src/index.ts index 862efef..7c3a5b1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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"; diff --git a/src/utils/spawner.ts b/src/utils/spawner.ts new file mode 100644 index 0000000..73d338b --- /dev/null +++ b/src/utils/spawner.ts @@ -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 void>(); + + function update(set: Set) { + 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, + spawner: SpawnerFunction, +) { + const update = createSpawner(spawner); + + return effect(() => { + const set = new Set(); + for (const each of iterable()) { + set.add(each); + } + update(set); + }); +}