Replace ref+tick workaround with proper state in useBestiary

Store creature map in useState instead of useRef with a dummy
tick counter. React now re-renders naturally when the map changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-03-14 12:54:48 +01:00
parent 36dcfc5076
commit 971e0ded49

View File

@@ -3,7 +3,7 @@ import type {
Creature, Creature,
CreatureId, CreatureId,
} from "@initiative/domain"; } from "@initiative/domain";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { import {
normalizeBestiary, normalizeBestiary,
setSourceDisplayNames, setSourceDisplayNames,
@@ -33,8 +33,9 @@ interface BestiaryHook {
export function useBestiary(): BestiaryHook { export function useBestiary(): BestiaryHook {
const [isLoaded, setIsLoaded] = useState(false); const [isLoaded, setIsLoaded] = useState(false);
const creatureMapRef = useRef<Map<CreatureId, Creature>>(new Map()); const [creatureMap, setCreatureMap] = useState(
const [, setTick] = useState(0); () => new Map<CreatureId, Creature>(),
);
useEffect(() => { useEffect(() => {
const index = loadBestiaryIndex(); const index = loadBestiaryIndex();
@@ -44,8 +45,7 @@ export function useBestiary(): BestiaryHook {
} }
bestiaryCache.loadAllCachedCreatures().then((map) => { bestiaryCache.loadAllCachedCreatures().then((map) => {
creatureMapRef.current = map; setCreatureMap(map);
setTick((t) => t + 1);
}); });
}, []); }, []);
@@ -63,9 +63,12 @@ export function useBestiary(): BestiaryHook {
})); }));
}, []); }, []);
const getCreature = useCallback((id: CreatureId): Creature | undefined => { const getCreature = useCallback(
return creatureMapRef.current.get(id); (id: CreatureId): Creature | undefined => {
}, []); return creatureMap.get(id);
},
[creatureMap],
);
const isSourceCachedFn = useCallback( const isSourceCachedFn = useCallback(
(sourceCode: string): Promise<boolean> => { (sourceCode: string): Promise<boolean> => {
@@ -86,10 +89,13 @@ export function useBestiary(): BestiaryHook {
const creatures = normalizeBestiary(json); const creatures = normalizeBestiary(json);
const displayName = getSourceDisplayName(sourceCode); const displayName = getSourceDisplayName(sourceCode);
await bestiaryCache.cacheSource(sourceCode, displayName, creatures); await bestiaryCache.cacheSource(sourceCode, displayName, creatures);
setCreatureMap((prev) => {
const next = new Map(prev);
for (const c of creatures) { for (const c of creatures) {
creatureMapRef.current.set(c.id, c); next.set(c.id, c);
} }
setTick((t) => t + 1); return next;
});
}, },
[], [],
); );
@@ -100,18 +106,20 @@ export function useBestiary(): BestiaryHook {
const creatures = normalizeBestiary(jsonData as any); const creatures = normalizeBestiary(jsonData as any);
const displayName = getSourceDisplayName(sourceCode); const displayName = getSourceDisplayName(sourceCode);
await bestiaryCache.cacheSource(sourceCode, displayName, creatures); await bestiaryCache.cacheSource(sourceCode, displayName, creatures);
setCreatureMap((prev) => {
const next = new Map(prev);
for (const c of creatures) { for (const c of creatures) {
creatureMapRef.current.set(c.id, c); next.set(c.id, c);
} }
setTick((t) => t + 1); return next;
});
}, },
[], [],
); );
const refreshCache = useCallback(async (): Promise<void> => { const refreshCache = useCallback(async (): Promise<void> => {
const map = await bestiaryCache.loadAllCachedCreatures(); const map = await bestiaryCache.loadAllCachedCreatures();
creatureMapRef.current = map; setCreatureMap(map);
setTick((t) => t + 1);
}, []); }, []);
return { return {