@redocly/theme
Version:
Shared UI components lib
40 lines (32 loc) • 1.16 kB
text/typescript
import { useState, useEffect, useCallback } from 'react';
import { isBrowser } from '../utils/js-utils';
function getStoredValue<T>(key: string, fallback: T): T {
if (!isBrowser()) return fallback;
try {
const savedValue = localStorage.getItem(key);
return savedValue ? (JSON.parse(savedValue) as T) : fallback;
} catch {
return fallback;
}
}
export function useLocalState<T>(key: string, initialValue: T): [T, (value: T) => void] {
const [value, setValue] = useState<T>(initialValue);
// Load stored value from localStorage after component mounts
// This ensures SSR compatibility: server and client both start with initialValue,
// then client loads the actual stored value without hydration mismatch
useEffect(() => {
if (!isBrowser()) return;
setValue(getStoredValue(key, initialValue));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [key]);
const handleSetValue = useCallback(
(newValue: T) => {
setValue(newValue);
if (isBrowser()) {
localStorage.setItem(key, JSON.stringify(newValue));
}
},
[key],
);
return [value, handleSetValue] as const;
}