diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx index 494d9d0..d729ab0 100644 --- a/apps/web/src/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -4,6 +4,7 @@ import { Outfit, Fira_Code } from "next/font/google"; import { AuthProvider } from "@/lib/auth/auth-context"; import { ErrorBoundary } from "@/components/error-boundary"; import { ThemeProvider } from "@/providers/ThemeProvider"; +import { ReactQueryProvider } from "@/providers/ReactQueryProvider"; import "./globals.css"; export const dynamic = "force-dynamic"; @@ -56,9 +57,11 @@ export default function RootLayout({ children }: { children: ReactNode }): React - - {children} - + + + {children} + + diff --git a/apps/web/src/providers/ReactQueryProvider.tsx b/apps/web/src/providers/ReactQueryProvider.tsx new file mode 100644 index 0000000..4bb193c --- /dev/null +++ b/apps/web/src/providers/ReactQueryProvider.tsx @@ -0,0 +1,28 @@ +"use client"; + +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { useState, type ReactNode } from "react"; + +interface ReactQueryProviderProps { + children: ReactNode; +} + +export function ReactQueryProvider({ children }: ReactQueryProviderProps): React.JSX.Element { + // Create a stable QueryClient per component mount (one per app session) + const [queryClient] = useState( + () => + new QueryClient({ + defaultOptions: { + queries: { + // Don't refetch on window focus in a dashboard context + refetchOnWindowFocus: false, + // Stale time of 30s — short enough for live data, avoids hammering + staleTime: 30_000, + retry: 1, + }, + }, + }) + ); + + return {children}; +}