With my site I am using Tanstack react-query. Now caching seems to work when navigating between pages and I can confirm that by checking the network log and no extra calls are made.
Now is it fair to say that when I refresh, it is normal for it to make an API request and that when you refresh the page with F5, the entire application reloads, including the React Query cache and my only option there is to use React persistent query i.e. indexed db?
My implementation works as follows:
react-query-provider.tsx:
'use client';
import { useState } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
export function ReactQueryProvider(props: React.PropsWithChildren) {
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
// With SSR, we usually want to set some default staleTime
// above 0 to avoid refetching immediately on the client
staleTime: 60 * 60 * 1000, // 60 minutes
gcTime: 60 * 60 * 1000, // 60 minutes (changed from 24h)
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
retry: 1,
},
},
}),
);
return (
<QueryClientProvider client={queryClient}>
{props.children}
</QueryClientProvider>
);
}
Then I have a rootprovider.tsx which is in my layout.tsx:
export function RootProviders({
lang,
theme = appConfig.theme,
children,
}: React.PropsWithChildren<{
lang: string;
theme?: string;
}>) {
const i18nSettings = useMemo(() => getI18nSettings(lang), [lang]);
return (
<MonitoringProvider>
<AppEventsProvider>
<AnalyticsProvider>
<ReactQueryProvider>
<I18nProvider settings={i18nSettings} resolver={i18nResolver}>
<CaptchaProvider>
<CaptchaTokenSetter siteKey={captchaSiteKey} />
<AuthProvider>
<ThemeProvider
attribute="class"
enableSystem
disableTransitionOnChange
defaultTheme={theme}
enableColorScheme={false}
>
{children}
</ThemeProvider>
</AuthProvider>
</CaptchaProvider>
<If condition={featuresFlagConfig.enableVersionUpdater}>
<VersionUpdater />
</If>
</I18nProvider>
</ReactQueryProvider>
</AnalyticsProvider>
</AppEventsProvider>
</MonitoringProvider>
);
}
And then I make calls to an api like :
const CACHE_SETTINGS = {
staleTime: getMillisecondsUntil5AMUTC(), // Cache until 5 AM UTC
gcTime: getMillisecondsUntil5AMUTC(), // Cache until 5 AM UTC
structuralSharing: true,
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
retry: (failureCount: number, error: any) => {
// Don't retry on 504 Gateway Timeout errors
if (error?.response?.status === 504) {
return false;
}
// For other errors, only retry once
return failureCount < 1;
},
} as const;
// Individual hooks for each data type
export function useRiskClients(filters?: { filter_column: string; column_equals: string }) {
const accountSlug = getAccountFromUrl();
return useQuery({
queryKey: ['riskClients', accountSlug, filters?.filter_column, filters?.column_equals],
queryFn: async () => {
const data = await fetchChartData<RiskClientResponse>(
'risk_hub/risk_clients',
filters
);
if (!data?.data) {
return {
data: [],
count: 0,
sum_of_mrr: 0
};
}
const transformed = {
count: data.count,
sum_of_mrr: data.sum_of_mrr,
data: data.data.map(client => ({
accountId: client.AccountId,
name: client.AccountName,
locations: (client.LocationNames || []).filter((loc): loc is string => loc !== null),
mrr: client.SumMRR,
riskLevel: client.RiskLevel,
nextRenewalDate: client.NextRenewalDateDiff,
unitType: client.LocationAssetType,
riskCategory: client.RiskType,
riskDescription: client.Description,
numberOfDesks: client.NumberOfDesks,
}))
};
return transformed;
},
...CACHE_SETTINGS
});
}
Is there anything technically wrong with this implementation and it's working as it should and is my only option to use persistent query If I need it to cache on refresh?