dressed_for_succes_store/frontend/hooks/useAdminCache.ts

192 lines
5.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useEffect, useCallback, useRef } from 'react';
/**
* Интерфейс для кэшированных данных
*/
interface CacheItem<T> {
data: T;
timestamp: number;
}
/**
* Интерфейс для опций хука
*/
interface UseAdminCacheOptions {
key: string;
ttl?: number; // Время жизни кэша в миллисекундах
storage?: 'memory' | 'session' | 'local';
}
/**
* Глобальный кэш для хранения данных в памяти
*/
const memoryCache = new Map<string, CacheItem<any>>();
/**
* Хук для кэширования данных в админке
* @param options Опции хука
* @returns Объект с функциями и состоянием
*/
export function useAdminCache<T>(options: UseAdminCacheOptions) {
const {
key,
ttl = 5 * 60 * 1000, // 5 минут по умолчанию
storage = 'memory'
} = options;
const [data, setData] = useState<T | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
const timerRef = useRef<NodeJS.Timeout | null>(null);
/**
* Получение данных из кэша
*/
const getFromCache = useCallback((): CacheItem<T> | null => {
try {
if (storage === 'memory') {
return memoryCache.get(key) as CacheItem<T> || null;
} else if (storage === 'session') {
const item = sessionStorage.getItem(`admin_cache_${key}`);
return item ? JSON.parse(item) : null;
} else if (storage === 'local') {
const item = localStorage.getItem(`admin_cache_${key}`);
return item ? JSON.parse(item) : null;
}
return null;
} catch (error) {
console.error('Ошибка при получении данных из кэша:', error);
return null;
}
}, [key, storage]);
/**
* Сохранение данных в кэш
*/
const saveToCache = useCallback((value: T) => {
try {
const cacheItem: CacheItem<T> = {
data: value,
timestamp: Date.now()
};
if (storage === 'memory') {
memoryCache.set(key, cacheItem);
} else if (storage === 'session') {
sessionStorage.setItem(`admin_cache_${key}`, JSON.stringify(cacheItem));
} else if (storage === 'local') {
localStorage.setItem(`admin_cache_${key}`, JSON.stringify(cacheItem));
}
// Устанавливаем таймер для очистки кэша
if (timerRef.current) {
clearTimeout(timerRef.current);
}
timerRef.current = setTimeout(() => {
invalidateCache();
}, ttl);
} catch (error) {
console.error('Ошибка при сохранении данных в кэш:', error);
}
}, [key, ttl, storage]);
/**
* Инвалидация кэша
*/
const invalidateCache = useCallback(() => {
try {
if (storage === 'memory') {
memoryCache.delete(key);
} else if (storage === 'session') {
sessionStorage.removeItem(`admin_cache_${key}`);
} else if (storage === 'local') {
localStorage.removeItem(`admin_cache_${key}`);
}
if (timerRef.current) {
clearTimeout(timerRef.current);
timerRef.current = null;
}
} catch (error) {
console.error('Ошибка при инвалидации кэша:', error);
}
}, [key, storage]);
/**
* Проверка актуальности кэша
*/
const isCacheValid = useCallback((): boolean => {
const cacheItem = getFromCache();
if (!cacheItem) return false;
const now = Date.now();
return now - cacheItem.timestamp < ttl;
}, [getFromCache, ttl]);
/**
* Загрузка данных из кэша при монтировании компонента
*/
useEffect(() => {
const loadFromCache = () => {
const cacheItem = getFromCache();
if (cacheItem && isCacheValid()) {
setData(cacheItem.data);
}
};
loadFromCache();
// Очистка таймера при размонтировании компонента
return () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
};
}, [getFromCache, isCacheValid]);
/**
* Установка данных с сохранением в кэш
*/
const setDataWithCache = useCallback((value: T) => {
setData(value);
saveToCache(value);
}, [saveToCache]);
/**
* Загрузка данных с использованием функции загрузки
*/
const loadData = useCallback(async (loadFn: () => Promise<T>) => {
try {
// Проверяем наличие данных в кэше
if (isCacheValid()) {
const cacheItem = getFromCache();
if (cacheItem) {
setData(cacheItem.data);
return cacheItem.data;
}
}
// Если данных в кэше нет или они устарели, загружаем новые
setIsLoading(true);
const newData = await loadFn();
setDataWithCache(newData);
setIsLoading(false);
return newData;
} catch (error) {
console.error('Ошибка при загрузке данных:', error);
setIsLoading(false);
return null;
}
}, [getFromCache, isCacheValid, setDataWithCache]);
return {
data,
isLoading,
setData: setDataWithCache,
invalidateCache,
loadData
};
}
export default useAdminCache;