Fix local/session storage parsing/stringifying values

The old logic stringifyed all values, including strings, which caused problems with reading external stored values (e.g., mui-mode) via the "useStorage" hook.
This commit is contained in:
schroda
2025-07-28 02:30:25 +02:00
parent fb00f51107
commit ef6c1fce56
4 changed files with 26 additions and 10 deletions

View File

@@ -30,10 +30,11 @@
<script type="module" src="./src/index.tsx"></script> <script type="module" src="./src/index.tsx"></script>
<script> <script>
const backgroundColor = (() => { const backgroundColor = (() => {
const storageValue = window.localStorage.getItem("theme_background")
try { try {
return JSON.parse(window.localStorage.getItem("theme_background")) return JSON.parse(storageValue)
} catch (e) { } catch (e) {
return null return storageValue
} }
})(); })();

View File

@@ -26,7 +26,7 @@ export class Storage {
return this.parseValue(this.getItem(key), defaultValue); return this.parseValue(this.getItem(key), defaultValue);
} }
setItem(key: string, value: unknown, emitEvent: boolean = true, stringify: boolean = true): void { setItem(key: string, value: unknown, emitEvent: boolean = true): void {
const currentValue = this.getItem(key); const currentValue = this.getItem(key);
const fireEvent = (valueToStore: string | undefined) => { const fireEvent = (valueToStore: string | undefined) => {
@@ -49,9 +49,10 @@ export class Storage {
return; return;
} }
const stringify = typeof value !== 'string';
const valueToStore = stringify ? JSON.stringify(value) : value; const valueToStore = stringify ? JSON.stringify(value) : value;
this.storage.setItem(key, valueToStore as string); this.storage.setItem(key, valueToStore);
fireEvent(valueToStore as string); fireEvent(valueToStore as string);
} }
} }

View File

@@ -8,6 +8,7 @@
import { Dispatch, Reducer, SetStateAction, useCallback, useMemo, useReducer, useSyncExternalStore } from 'react'; import { Dispatch, Reducer, SetStateAction, useCallback, useMemo, useReducer, useSyncExternalStore } from 'react';
import { AppStorage, Storage } from '@/lib/storage/AppStorage.ts'; import { AppStorage, Storage } from '@/lib/storage/AppStorage.ts';
import { jsonSaveParse } from '@/lib/HelperFunctions.ts';
const subscribeToStorageUpdates = (callback: () => void) => { const subscribeToStorageUpdates = (callback: () => void) => {
window.addEventListener('storage', callback); window.addEventListener('storage', callback);
@@ -31,16 +32,29 @@ function useStorage<T>(
const setValue = useCallback<React.Dispatch<React.SetStateAction<T | undefined>>>( const setValue = useCallback<React.Dispatch<React.SetStateAction<T | undefined>>>(
(value) => { (value) => {
// Allow value to be a function so we have same API as useState // Allow value to be a function so we have same API as useState
const valueToStore = value instanceof Function ? value(storage.getItemParsed(key, initialState)) : value; const valueToStore = (() => {
if (value instanceof Function) {
const previousValue =
jsonSaveParse(storage.getItem(key) ?? '') ?? storage.getItemParsed(key, initialState);
return value(previousValue);
}
return value;
})();
storage.setItem(key, valueToStore); storage.setItem(key, valueToStore);
}, },
[key], [key],
); );
const storedValue = useMemo( const storedValue = useMemo(() => {
() => (storedValueRaw !== null ? JSON.parse(storedValueRaw) : initialState), if (storedValueRaw === null) {
[storedValueRaw, key], return initialState;
); }
return jsonSaveParse(storedValueRaw) ?? storedValueRaw;
}, [storedValueRaw, key]);
return [storedValue, setValue]; return [storedValue, setValue];
} }

View File

@@ -86,7 +86,7 @@ export const Appearance = () => {
setThemeMode(newMode as ThemeMode); setThemeMode(newMode as ThemeMode);
setMode(newMode); setMode(newMode);
// in case a non "colorSchemes" mui theme is active, "setMode" does not update the mode ("mui-mode") value // in case a non "colorSchemes" mui theme is active, "setMode" does not update the mode ("mui-mode") value
AppStorage.local.setItem('mui-mode', newMode, true, false); AppStorage.local.setItem('mui-mode', newMode, true);
}} }}
> >
<MenuItem key={ThemeMode.SYSTEM} value={ThemeMode.SYSTEM}> <MenuItem key={ThemeMode.SYSTEM} value={ThemeMode.SYSTEM}>