feat(framework): decouple spawner update logic

Extract the core update logic from `spawnEffect` into
`createSpawnUpdate`.
This allows manual updates of spawned objects without relying on
Preact effects, which is useful for non-reactive or imperative
update cycles.

Refactor `Buff` and `BuffSpawner` in `sts-like-viewer` to use the new
`createSpawnUpdate` API for more efficient buff rendering.
This commit is contained in:
2026-04-22 20:59:35 +08:00
parent 447a5cfbd0
commit c29b9a43b3
5 changed files with 203 additions and 50 deletions
+2 -2
View File
@@ -8,8 +8,8 @@ export type { DragDropEvent, DragDropCallback } from "./utils";
export { hoverEffect } from "./utils";
// Data-driven object spawning
export { spawnEffect } from "./spawner";
export type { Spawner } from "./spawner";
export { spawnEffect, createSpawnUpdate } from "./spawner";
export type { Spawner, SpawnerCallback } from "./spawner";
// Scene base classes
export {
+25 -7
View File
@@ -4,9 +4,7 @@ import type Phaser from "phaser";
type GO = Phaser.GameObjects.GameObject;
export interface Spawner<TData, TObject extends GO = GO> {
/** 数据源迭代器 */
getData(): Iterable<TData>;
export interface SpawnerCallback<TData, TObject extends GO = GO> {
/** 获取数据的唯一键 */
getKey(t: TData): string;
/** 创建新对象 */
@@ -17,15 +15,33 @@ export interface Spawner<TData, TObject extends GO = GO> {
onUpdate(t: TData, obj: TObject): void;
}
export interface Spawner<
TData,
TObject extends GO = GO,
> extends SpawnerCallback<TData, TObject> {
/** 数据源迭代器 */
getData(): Iterable<TData>;
}
export function spawnEffect<TData, TObject extends GO = GO>(
spawner: Spawner<TData, TObject>,
): () => void {
const entries = new Map<string, { object: TObject; data: TData }>();
) {
const update = createSpawnUpdate(spawner);
return effect(() => {
update(spawner.getData());
});
}
export function createSpawnUpdate<TData, TObject extends GO = GO>(
spawner: SpawnerCallback<TData, TObject>,
) {
const entries = new Map<string, { object: TObject; data: TData }>();
function update(data: Iterable<TData>) {
const current = new Set<string>();
for (const t of spawner.getData()) {
for (const t of data) {
const key = spawner.getKey(t);
current.add(key);
@@ -48,5 +64,7 @@ export function spawnEffect<TData, TObject extends GO = GO>(
entries.delete(key);
}
}
});
}
return update;
}