51 lines
1.4 KiB
TypeScript
51 lines
1.4 KiB
TypeScript
|
import React from 'react'
|
||
|
import {
|
||
|
getLocalStorageItem,
|
||
|
removeLocalStorageItem,
|
||
|
setLocalStorageItem
|
||
|
} from 'utils'
|
||
|
|
||
|
const useLocalStorageSubscribe = (callback: () => void) => {
|
||
|
window.addEventListener('storage', callback)
|
||
|
return () => window.removeEventListener('storage', callback)
|
||
|
}
|
||
|
|
||
|
export function useLocalStorage<T>(
|
||
|
key: string,
|
||
|
initialValue: T
|
||
|
): [T, React.Dispatch<React.SetStateAction<T>>] {
|
||
|
const getSnapshot = () => getLocalStorageItem(key, initialValue)
|
||
|
|
||
|
const data = React.useSyncExternalStore(useLocalStorageSubscribe, getSnapshot)
|
||
|
|
||
|
const setState: React.Dispatch<React.SetStateAction<T>> = React.useCallback(
|
||
|
(v: React.SetStateAction<T>) => {
|
||
|
try {
|
||
|
const nextState =
|
||
|
typeof v === 'function'
|
||
|
? (v as (prevState: T) => T)(JSON.parse(data))
|
||
|
: v
|
||
|
|
||
|
if (nextState === undefined || nextState === null) {
|
||
|
removeLocalStorageItem(key)
|
||
|
} else {
|
||
|
setLocalStorageItem(key, JSON.stringify(nextState))
|
||
|
}
|
||
|
} catch (e) {
|
||
|
console.warn(e)
|
||
|
}
|
||
|
},
|
||
|
[key, data]
|
||
|
)
|
||
|
|
||
|
React.useEffect(() => {
|
||
|
// Set local storage only when it's empty
|
||
|
const data = window.localStorage.getItem(key)
|
||
|
if (data === null) {
|
||
|
setLocalStorageItem(key, JSON.stringify(initialValue))
|
||
|
}
|
||
|
}, [key, initialValue])
|
||
|
|
||
|
return [JSON.parse(data) as T, setState]
|
||
|
}
|