import {computed, ComputedRef, readonly, ref, unref} from "vue"; import {Dispatch, SetStateAction, useState} from './index'; import {isBrowser, noop} from './misc/util'; type parserOptions = | { raw: true; } | { raw: false; serializer: (value: T) => string; deserializer: (value: string) => T; }; export default function useLocalStorage( key: string, initialValue?: T, options?: parserOptions ) { if (!isBrowser) { return [computed(() => unref(initialValue)), noop, noop]; } if (!key) { throw new Error('useLocalStorage key may not be falsy'); } const deserializer = options ? options.raw ? (value) => value : options.deserializer : JSON.parse; // eslint-disable-next-line react-hooks/rules-of-hooks const [state, setState] = useState(() => { try { const serializer = options ? (options.raw ? String : options.serializer) : JSON.stringify; const localStorageValue = localStorage.getItem(key); if (localStorageValue !== null) { return deserializer(localStorageValue); } else { initialValue && localStorage.setItem(key, serializer(initialValue)); return initialValue; } } catch { // If user is in private mode or has storage restriction // localStorage can throw. JSON.parse and JSON.stringify // can throw, too. return initialValue; } }); // eslint-disable-next-line react-hooks/rules-of-hooks const set: Dispatch> = (valOrFunc) => { try { const newState = typeof valOrFunc === 'function' ? (valOrFunc as Function)(state) : valOrFunc; if (typeof newState === 'undefined') { return } let value: string; if (options) if (options.raw) { if (typeof newState === 'string') { value = newState; } else { value = JSON.stringify(newState); } } else if (options.serializer) { value = options.serializer(newState); } else { value = JSON.stringify(newState); } else { value = JSON.stringify(newState); } localStorage.setItem(key, value); setState(deserializer(value)); } catch { // If user is in private mode or has storage restriction // localStorage can throw. Also JSON.stringify can throw. } }; // eslint-disable-next-line react-hooks/rules-of-hooks const remove = () => { try { localStorage.removeItem(key); setState(undefined); } catch { // If user is in private mode or has storage restriction // localStorage can throw. } }; return [computed(() => state.value), set, remove]; };