0

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?

1 Answer 1

0

For me, hitting F5 will clears in memory cache, which is expected I think.

If you want data to survive a page reload, persist the cache to storage. TanStack Query provides an official persistence plugin. You can also use IndexedDB for example (via an async persister) for larger payloads. Persistence restores the cache and continues to keep it in sync. You still control refetching behavior with staleTime, refetchOnMount, etc...

https://tanstack.com/query/v5/docs/framework/react/plugins/persistQueryClient/

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.