/* eslint-disable no-empty */ import { useState } from 'react'; import { useMemoizedFn } from '../useMemoizedFn'; import { useUpdateEffect } from '../useUpdateEffect'; import _isFunction from 'lodash/isFunction'; import _isUndefined from 'lodash/isUndefined'; export interface IFuncUpdater { (previousState?: T): T; } export interface IFuncStorage { (): Storage; } export interface Options { serializer?: (value: T) => string; deserializer?: (value: string) => T; defaultValue?: T | IFuncUpdater; } export function createUseStorageState(getStorage: () => Storage | undefined) { function useStorageState(key: string, options?: Options) { let storage: Storage | undefined; // https://github.com/alibaba/hooks/issues/800 try { storage = getStorage(); } catch (err) { console.error(err); } const serializer = (value: T) => { if (options?.serializer) { return options?.serializer(value); } return JSON.stringify(value); }; const deserializer = (value: string) => { if (options?.deserializer) { return options?.deserializer(value); } return JSON.parse(value); }; function getStoredValue() { try { const raw = storage?.getItem(key); if (raw) { return deserializer(raw); } } catch (e) { console.error(e); } if (_isFunction(options?.defaultValue)) { return options?.defaultValue(); } return options?.defaultValue; } const [state, setState] = useState(() => getStoredValue()); useUpdateEffect(() => { setState(getStoredValue()); }, [key]); const updateState = (value: T | IFuncUpdater) => { const currentState = _isFunction(value) ? value(state) : value; setState(currentState); if (_isUndefined(currentState)) { storage?.removeItem(key); } else { try { storage?.setItem(key, serializer(currentState)); } catch (e) { console.error(e); } } }; return [state, useMemoizedFn(updateState)] as const; } return useStorageState; }