UNPKG

pagamio-frontend-commons-lib

Version:

Pagamio library for Frontend reusable components like the form engine and table container

83 lines (82 loc) 3.57 kB
import { isEqual } from 'lodash'; import { useCallback, useEffect, useRef } from 'react'; import { useApiSWRWithMutation } from '../../api'; // Constants for cache control const CACHE_EXPIRY_TIME = 5 * 60 * 1000; // 5 minutes in milliseconds /** * Hook for fetching chart data with optimized caching to reduce server load * @template T The data type to be returned from the API * @template TransformReturnType The type after transformation */ export const useChartData = (url, query, transform) => { // Keep a reference to the last data received to compare with new data const lastDataRef = useRef(null); const lastFetchTimeRef = useRef(null); // Custom comparison function to determine if data has changed const isDataEqual = useCallback((a, b) => { return isEqual(a, b); }, []); // Custom cache comparison function for SWR to determine if data needs to be revalidated const compareCache = useCallback((cachedData, newData) => { const areEqual = isDataEqual(cachedData, newData); return areEqual; }, [isDataEqual]); const { data, error, isLoading: loading, refresh, } = useApiSWRWithMutation([url, query], { // Explicitly disable automatic polling/refreshing refreshInterval: 0, refreshWhenHidden: false, refreshWhenOffline: false, // Only revalidate on initial mount revalidateOnMount: true, revalidateOnFocus: false, revalidateOnReconnect: false, revalidateIfStale: false, // Set a long dedupe interval to prevent frequent requests for the same resource dedupingInterval: 300000, // 5 minutes method: 'POST', body: JSON.stringify(query), headers: { 'Content-Type': 'application/json', }, // Use SWR's compare function to avoid unnecessary renders and revalidations compare: compareCache, // Keep previous data while fetching new data keepPreviousData: true, // Handle successful responses and update cache metadata onSuccess: (data) => { // Store the data for comparison lastDataRef.current = data; lastFetchTimeRef.current = Date.now(); }, }); // Effect to update last fetch time when data changes useEffect(() => { if (data) { lastDataRef.current = data; lastFetchTimeRef.current = Date.now(); } }, [data]); const transformedData = transform ? transform(data) : data; const isEmpty = !error && !loading && Array.isArray(transformedData) ? !transformedData.length : transformedData === undefined; // Enhanced refresh function that uses intelligent caching without custom headers const smartRefresh = useCallback(() => { // Check if cache is still fresh (< 5 minutes old) const now = Date.now(); const lastFetchTime = lastFetchTimeRef.current; // If data was fetched less than 5 minutes ago, don't refresh if (lastFetchTime && now - lastFetchTime < CACHE_EXPIRY_TIME) { // Return a promise that resolves immediately to match the refresh API return Promise.resolve(); } // Otherwise, trigger a revalidation (standard SWR refresh, no custom headers) return refresh(); }, [refresh]); return { data: transformedData, error, loading, isEmpty, refresh: smartRefresh, lastRefreshed: lastFetchTimeRef.current ? new Date(lastFetchTimeRef.current) : undefined, }; };