mango-v4-ui/hooks/useLocalStorageState.ts

93 lines
2.2 KiB
TypeScript
Raw Normal View History

/* eslint-disable @typescript-eslint/no-explicit-any */
import {
useMemo,
useState,
useEffect,
useCallback,
SetStateAction,
Dispatch,
} from 'react'
2022-07-18 20:58:21 -07:00
interface LocalStorageListenersType {
[key: string]: Array<Dispatch<SetStateAction<string>>>
}
const localStorageListeners: LocalStorageListenersType = {}
2022-07-18 20:58:21 -07:00
function useLocalStorageStringState(
2022-07-18 20:58:21 -07:00
key: string,
2023-07-21 11:47:53 -07:00
defaultState: string,
): [string | undefined, (newState: string) => void] {
2022-07-18 20:58:21 -07:00
const state =
typeof window !== 'undefined'
? localStorage.getItem(key) || defaultState
: defaultState || ''
const [, notify] = useState(key + '\n' + state)
useEffect(() => {
if (!localStorageListeners[key]) {
localStorageListeners[key] = []
}
localStorageListeners[key].push(notify)
return () => {
localStorageListeners[key] = localStorageListeners[key].filter(
2023-07-21 11:47:53 -07:00
(listener) => listener !== notify,
2022-07-18 20:58:21 -07:00
)
if (localStorageListeners[key].length === 0) {
delete localStorageListeners[key]
}
}
}, [key])
const setState = useCallback<(newState: string | null) => void>(
(newState) => {
if (!localStorageListeners[key]) {
localStorageListeners[key] = []
}
if (newState === null) {
localStorage.removeItem(key)
} else {
localStorage.setItem(key, newState)
}
2023-02-27 23:20:11 -08:00
localStorageListeners[key].forEach((listener) =>
2023-07-21 11:47:53 -07:00
listener(key + '\n' + newState),
2022-07-18 20:58:21 -07:00
)
},
2023-07-21 11:47:53 -07:00
[key],
2022-07-18 20:58:21 -07:00
)
return [state, setState]
}
export default function useLocalStorageState<T = any>(
2022-07-18 20:58:21 -07:00
key: string,
2023-07-21 11:47:53 -07:00
defaultState?: string | number | object | undefined | null | boolean,
): [T, (newState: string | number | object | null | boolean) => void] {
2022-07-18 20:58:21 -07:00
const [stringState, setStringState] = useLocalStorageStringState(
key,
2023-07-21 11:47:53 -07:00
JSON.stringify(defaultState),
2022-07-18 20:58:21 -07:00
)
const setState = useCallback(
(newState: string | number | object | null | boolean) => {
setStringState(JSON.stringify(newState))
},
2023-07-21 11:47:53 -07:00
[setStringState],
)
const state: T = useMemo(() => {
if (stringState) {
try {
return JSON.parse(stringState)
} catch (e) {
2023-03-02 17:18:52 -08:00
console.log('Error parsing JSON from localStorage', e)
return stringState
}
}
}, [stringState])
return [state, setState]
2022-07-18 20:58:21 -07:00
}