You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
spa_instat_tv/src/hooks/useStorage/index.tsx

87 lines
2.8 KiB

/* 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<T> = {
clearOnUnmount?: boolean,
/**
* Дефолтное знаение
* используется если полученный из сторежда значение не валидно
*/
defaultValue?: T,
/**
* Начальное значение
* если указано пропускает считывание из стореджа
*/
initialValue?: T,
key: string,
serialize?: (key: string, value: T) => string,
/**
* функция для валидации полученного значения из стора
* если значение не валидно то используется defaultValue.
* Если не передан валидатор то полученное значение из стореджа
* считается валидным.
*/
validator?: (value: T) => boolean,
}
/**
* Хук высшего порядка, получает сторедж
* и возвращает хук работающий с данным стореджем
* Хук считывает значение из стора и использует как начальное значение стейта,
* при вызове сеттера обновляется сторедж и реакт стейет
*/
const createHook = (storage: Storage) => (
<T extends any>({
clearOnUnmount,
defaultValue,
initialValue,
key,
serialize = defaultSerializer,
validator = defaultValidator,
}: Args<T>) => {
const getInitialState = () => {
const storeValue = readStorageInitialValue(storage, key)
const isValid = validator(storeValue)
return isValid ? storeValue : defaultValue
}
const [state, setState] = useState<T>(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)