/** * Kleiner Store für Werte, die einen Reload überleben sollen. * * Warum kein `useState` + `useEffect`: Beim Serverrendering gibt es keinen * localStorage. Lädt man den gespeicherten Wert nachträglich im Effekt, löst * das eine zweite Renderrunde aus (und React beanstandet das zu Recht). * `useSyncExternalStore` ist genau für diesen Fall gebaut: Es rendert * serverseitig den Standardwert und wechselt nach der Hydration auf den * gespeicherten, ohne Mismatch und ohne Zusatzrender. */ export interface PersistenterStore { subscribe: (hoerer: () => void) => () => void; getSnapshot: () => T; getServerSnapshot: () => T; setzen: (naechster: T | ((vorher: T) => T)) => void; } export function erstellePersistentenStore( schluessel: string, standard: T, /** Gelesene Daten mit dem Standard verschmelzen: fängt alte Formate ab. */ zusammenfuehren: (gespeichert: unknown, standard: T) => T = (g, s) => ({ ...s, ...(g as object) }) as T ): PersistenterStore { let wert = standard; let gelesen = false; const hoerer = new Set<() => void>(); function lade(): T { if (gelesen || typeof window === "undefined") return wert; gelesen = true; try { const roh = window.localStorage.getItem(schluessel); if (roh) wert = zusammenfuehren(JSON.parse(roh), standard); } catch { // Defektes JSON oder gesperrter Storage: beim Standard bleiben. } return wert; } return { subscribe(neuerHoerer) { hoerer.add(neuerHoerer); return () => hoerer.delete(neuerHoerer); }, getSnapshot: () => lade(), getServerSnapshot: () => standard, setzen(naechster) { lade(); wert = typeof naechster === "function" ? (naechster as (v: T) => T)(wert) : naechster; try { window.localStorage.setItem(schluessel, JSON.stringify(wert)); } catch { // Privater Modus o. Ä.: Persistenz ist optional. } hoerer.forEach((h) => h()); }, }; }