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.
87 lines
2.8 KiB
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)
|
|
|