@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
JavaScript
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,
};
};