import { Dispatch, SetStateAction } from 'react'; import { useEffectDeepCompare } from './useEffectDeepCompare'; import { useLocalStorage } from './useLocalStorage'; import { useSetState } from './useSetState'; export type UsePersistentStateResult = [ state: T, setState: Dispatch>>, remove: () => void, ]; export interface UsePersistentStateOptions { /** * Check if the saved state keys are different from the initial state and override it if needed. * @default false */ overrideDivergentSavedState?: boolean; /** * Reset properties in the saved state. */ resetProperties?: Partial; } function getState( initialState: TState, savedState: TState, shouldOverride: boolean, restoreProperties?: Partial, ): TState { if (shouldOverride) { const initialStateKeys = Object.keys(initialState); const savedStateKeys = savedState ? Object.keys(savedState) : []; const restorePropertiesKeys = restoreProperties ? Object.keys(restoreProperties) : []; if (![...initialStateKeys, ...restorePropertiesKeys].every(k => savedStateKeys.includes(k))) { return { ...initialState, ...restoreProperties }; } return { ...savedState, ...restoreProperties }; } return { ...savedState, ...restoreProperties }; } export function usePersistentState( key: string, initialState: TState, options?: UsePersistentStateOptions, ): UsePersistentStateResult { const { overrideDivergentSavedState = false, resetProperties } = options || {}; const [value, setValue, remove] = useLocalStorage(key, initialState); const [state, setState] = useSetState( getState(initialState, value!, overrideDivergentSavedState, resetProperties), ); useEffectDeepCompare(() => { setValue(state); }, [setValue, state]); return [state, setState, remove]; }