/* eslint-disable @typescript-eslint/no-explicit-any */ import { useState, useEffect } from 'react' import { queryParamStorage } from 'features/QueryParamsStorage' import { readStorageInitialValue } from './helpers' const defaultValidator = () => true const defaultSerializer = (key: string, value: any) => value type Args = { clearOnUnmount?: boolean, /** * Дефолтное знаение * используется если полученный из сторежда значение не валидно */ defaultValue?: T, /** * Начальное значение * если указано пропускает считывание из стореджа */ initialValue?: T, key: string, serialize?: (key: string, value: T) => string, /** * функция для валидации полученного значения из стора * если значение не валидно то используется defaultValue. * Если не передан валидатор то полученное значение из стореджа * считается валидным. */ validator?: (value: T) => boolean, } /** * Хук высшего порядка, получает сторедж * и возвращает хук работающий с данным стореджем * Хук считывает значение из стора и использует как начальное значение стейта, * при вызове сеттера обновляется сторедж и реакт стейет */ const createHook = (storage: Storage) => ( ({ clearOnUnmount, defaultValue, initialValue, key, serialize = defaultSerializer, validator = defaultValidator, }: Args) => { const getInitialState = () => { const storeValue = readStorageInitialValue(storage, key) const isValid = validator(storeValue) return isValid ? storeValue : defaultValue } const [state, setState] = useState(initialValue || getInitialState) useEffect(() => { const storeValue = readStorageInitialValue(storage, key) const isValid = validator(storeValue) if (!isValid) { storage.removeItem(key) } }, [key, validator]) useEffect(() => { storage.setItem(key, JSON.stringify(serialize(key, state))) }, [ key, state, serialize, ]) useEffect(() => { if (clearOnUnmount) return () => storage.removeItem(key) return undefined }, [key, clearOnUnmount]) return [state, setState] as const } ) export const useLocalStore = createHook(localStorage) export const useSessionStore = createHook(sessionStorage) export const useQueryParamStore = createHook(queryParamStorage)