mars-v2-frontend/src/hooks/useLocalStorage.ts

56 lines
1.5 KiB
TypeScript

import { useCallback, useEffect, useRef, useState } from 'react'
import useStore from 'store'
export default function useLocalStorage<T>(key: string, defaultValue: T): [T, (value: T) => void] {
const keyRef = useRef(key)
const defaultValueRef = useRef(defaultValue)
const [value, _setValue] = useState(defaultValueRef.current)
const updateValue = useCallback((value: T) => {
useStore.setState({ [keyRef.current]: value })
_setValue(value)
}, [])
useEffect(() => {
const savedItem = localStorage.getItem(keyRef.current)
if (!savedItem) {
localStorage.setItem(keyRef.current, JSON.stringify(defaultValueRef.current))
}
updateValue(savedItem ? JSON.parse(savedItem) : defaultValueRef.current)
function handler(e: StorageEvent) {
if (e.key !== keyRef.current) return
const item = localStorage.getItem(keyRef.current)
updateValue(JSON.parse(item ?? JSON.stringify(defaultValueRef.current)))
}
window.addEventListener('storage', handler)
return () => {
window.removeEventListener('storage', handler)
}
}, [updateValue])
const setValue = useCallback(
(value: T) => {
try {
updateValue(value)
localStorage.setItem(keyRef.current, JSON.stringify(value))
if (typeof window !== 'undefined') {
window.dispatchEvent(new StorageEvent('storage', { key: keyRef.current }))
}
} catch (e) {
console.error(e)
}
},
[updateValue],
)
return [value, setValue]
}