From 36dcfc507691c695683cc2d743283c35c7630a7d Mon Sep 17 00:00:00 2001 From: Lukas Date: Sat, 14 Mar 2026 12:48:35 +0100 Subject: [PATCH] Use useOptimistic for instant source manager cache clearing Source rows disappear immediately when cleared instead of waiting for the IndexedDB operation to complete. Real state syncs after. Co-Authored-By: Claude Opus 4.6 --- apps/web/src/components/source-manager.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/apps/web/src/components/source-manager.tsx b/apps/web/src/components/source-manager.tsx index dd5e086..5422f42 100644 --- a/apps/web/src/components/source-manager.tsx +++ b/apps/web/src/components/source-manager.tsx @@ -1,5 +1,5 @@ import { Database, Trash2 } from "lucide-react"; -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useOptimistic, useState } from "react"; import type { CachedSourceInfo } from "../adapters/bestiary-cache.js"; import * as bestiaryCache from "../adapters/bestiary-cache.js"; import { Button } from "./ui/button.js"; @@ -10,6 +10,16 @@ interface SourceManagerProps { export function SourceManager({ onCacheCleared }: SourceManagerProps) { const [sources, setSources] = useState([]); + const [optimisticSources, applyOptimistic] = useOptimistic( + sources, + ( + state, + action: { type: "remove"; sourceCode: string } | { type: "clear" }, + ) => + action.type === "clear" + ? [] + : state.filter((s) => s.sourceCode !== action.sourceCode), + ); const loadSources = useCallback(async () => { const cached = await bestiaryCache.getCachedSources(); @@ -21,18 +31,20 @@ export function SourceManager({ onCacheCleared }: SourceManagerProps) { }, [loadSources]); const handleClearSource = async (sourceCode: string) => { + applyOptimistic({ type: "remove", sourceCode }); await bestiaryCache.clearSource(sourceCode); await loadSources(); onCacheCleared(); }; const handleClearAll = async () => { + applyOptimistic({ type: "clear" }); await bestiaryCache.clearAll(); await loadSources(); onCacheCleared(); }; - if (sources.length === 0) { + if (optimisticSources.length === 0) { return (
@@ -57,7 +69,7 @@ export function SourceManager({ onCacheCleared }: SourceManagerProps) {
    - {sources.map((source) => ( + {optimisticSources.map((source) => (