fix: trpc/react-query — only one query client should exist (#18179)
* use prefetch function in ScheduleListItem and refactor * modify app router trpc provider to match the original configs * revert unneeded change * move trpc provider up and do refactors * remove log * add comment * fix: Some typing style fixes --------- Co-authored-by: Alex van Andel <me@alexvanandel.com>
This commit is contained in:
co-authored by
Alex van Andel
parent
d12fc78fea
commit
f72748b6f2
@@ -1,14 +1,18 @@
|
||||
import { type DehydratedState, QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { HydrateClient } from "app/_trpc/HydrateClient";
|
||||
"use client";
|
||||
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { trpc } from "app/_trpc/client";
|
||||
import { useState } from "react";
|
||||
import superjson from "superjson";
|
||||
|
||||
import { httpBatchLink, httpLink, loggerLink, splitLink } from "@calcom/trpc/client";
|
||||
import { httpBatchLink, httpLink, loggerLink, splitLink, TRPCClientError } from "@calcom/trpc/client";
|
||||
import { ENDPOINTS } from "@calcom/trpc/react/shared";
|
||||
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
|
||||
|
||||
export type Endpoint = (typeof ENDPOINTS)[number];
|
||||
|
||||
const MAX_QUERY_RETRIES = 3;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const resolveEndpoint = (links: any) => {
|
||||
// TODO: Update our trpc routes so they are more clear.
|
||||
@@ -32,16 +36,44 @@ const resolveEndpoint = (links: any) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const TrpcProvider: React.FC<{ children: React.ReactNode; dehydratedState?: DehydratedState }> = ({
|
||||
children,
|
||||
dehydratedState,
|
||||
}) => {
|
||||
const isTRPCClientError = (cause: unknown): cause is TRPCClientError<AppRouter> => {
|
||||
return cause instanceof TRPCClientError;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export const TrpcProvider = ({ children }: Props) => {
|
||||
const [queryClient] = useState(
|
||||
() =>
|
||||
new QueryClient({
|
||||
defaultOptions: { queries: { staleTime: 5000 } },
|
||||
// these configurations are copied from "packages/trpc/react/trpc.ts"
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
/**
|
||||
* 1s should be enough to just keep identical query waterfalls low
|
||||
* @example if one page components uses a query that is also used further down the tree
|
||||
*/
|
||||
staleTime: 1000,
|
||||
/**
|
||||
* Retry `useQuery()` calls depending on this function
|
||||
*/
|
||||
retry(failureCount, error) {
|
||||
if (isTRPCClientError(error) && error.data) {
|
||||
const { code } = error.data;
|
||||
if (code === "BAD_REQUEST" || code === "FORBIDDEN" || code === "UNAUTHORIZED") {
|
||||
// if input data is wrong or you're not authorized there's no point retrying a query
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return failureCount < MAX_QUERY_RETRIES;
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const url =
|
||||
typeof window !== "undefined"
|
||||
? "/api/trpc"
|
||||
@@ -94,9 +126,7 @@ export const TrpcProvider: React.FC<{ children: React.ReactNode; dehydratedState
|
||||
|
||||
return (
|
||||
<trpc.Provider client={trpcClient} queryClient={queryClient}>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
{dehydratedState ? <HydrateClient state={dehydratedState}>{children}</HydrateClient> : children}
|
||||
</QueryClientProvider>
|
||||
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
||||
</trpc.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { TrpcProvider } from "app/_trpc/trpc-provider";
|
||||
import { dir } from "i18next";
|
||||
import { Inter } from "next/font/google";
|
||||
import localFont from "next/font/local";
|
||||
@@ -112,7 +113,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{children}
|
||||
<TrpcProvider>{children}</TrpcProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TooltipProvider } from "@radix-ui/react-tooltip";
|
||||
import { TrpcProvider } from "app/_trpc/trpc-provider";
|
||||
import { HydrateClient } from "app/_trpc/HydrateClient";
|
||||
import { dir } from "i18next";
|
||||
import type { Session } from "next-auth";
|
||||
import { SessionProvider, useSession } from "next-auth/react";
|
||||
@@ -265,43 +265,45 @@ function OrgBrandProvider({ children }: { children: React.ReactNode }) {
|
||||
const AppProviders = (props: PageWrapperProps) => {
|
||||
// No need to have intercom on public pages - Good for Page Performance
|
||||
const isBookingPage = useIsBookingPage();
|
||||
|
||||
const RemainingProviders = (
|
||||
<TrpcProvider dehydratedState={props.dehydratedState}>
|
||||
<EventCollectionProvider options={{ apiPath: "/api/collect-events" }}>
|
||||
<SessionProvider>
|
||||
<CustomI18nextProvider i18n={props.i18n}>
|
||||
<TooltipProvider>
|
||||
{/* color-scheme makes background:transparent not work which is required by embed. We need to ensure next-theme adds color-scheme to `body` instead of `html`(https://github.com/pacocoursey/next-themes/blob/main/src/index.tsx#L74). Once that's done we can enable color-scheme support */}
|
||||
<CalcomThemeProvider
|
||||
themeBasis={props.themeBasis}
|
||||
nonce={props.nonce}
|
||||
isThemeSupported={/* undefined gets treated as true */ props.isThemeSupported}
|
||||
isBookingPage={props.isBookingPage || isBookingPage}>
|
||||
<FeatureFlagsProvider>
|
||||
<OrgBrandProvider>
|
||||
{/* @ts-expect-error FIXME remove this comment when upgrading typescript to v5 */}
|
||||
<CacheProvider>
|
||||
<MetaProvider>{props.children}</MetaProvider>
|
||||
</CacheProvider>
|
||||
</OrgBrandProvider>
|
||||
</FeatureFlagsProvider>
|
||||
</CalcomThemeProvider>
|
||||
</TooltipProvider>
|
||||
</CustomI18nextProvider>
|
||||
</SessionProvider>
|
||||
</EventCollectionProvider>
|
||||
</TrpcProvider>
|
||||
<EventCollectionProvider options={{ apiPath: "/api/collect-events" }}>
|
||||
<SessionProvider>
|
||||
<CustomI18nextProvider i18n={props.i18n}>
|
||||
<TooltipProvider>
|
||||
{/* color-scheme makes background:transparent not work which is required by embed. We need to ensure next-theme adds color-scheme to `body` instead of `html`(https://github.com/pacocoursey/next-themes/blob/main/src/index.tsx#L74). Once that's done we can enable color-scheme support */}
|
||||
<CalcomThemeProvider
|
||||
themeBasis={props.themeBasis}
|
||||
nonce={props.nonce}
|
||||
isThemeSupported={/* undefined gets treated as true */ props.isThemeSupported}
|
||||
isBookingPage={props.isBookingPage || isBookingPage}>
|
||||
<FeatureFlagsProvider>
|
||||
<OrgBrandProvider>
|
||||
{/* @ts-expect-error FIXME remove this comment when upgrading typescript to v5 */}
|
||||
<CacheProvider>
|
||||
<MetaProvider>{props.children}</MetaProvider>
|
||||
</CacheProvider>
|
||||
</OrgBrandProvider>
|
||||
</FeatureFlagsProvider>
|
||||
</CalcomThemeProvider>
|
||||
</TooltipProvider>
|
||||
</CustomI18nextProvider>
|
||||
</SessionProvider>
|
||||
</EventCollectionProvider>
|
||||
);
|
||||
const Hydrated = props.dehydratedState ? (
|
||||
<HydrateClient state={props.dehydratedState}>{RemainingProviders}</HydrateClient>
|
||||
) : (
|
||||
RemainingProviders
|
||||
);
|
||||
|
||||
if (isBookingPage) {
|
||||
return RemainingProviders;
|
||||
return Hydrated;
|
||||
}
|
||||
|
||||
return (
|
||||
<DynamicHelpscoutProvider>
|
||||
<DynamicIntercomProvider>
|
||||
<DynamicPostHogProvider>{RemainingProviders}</DynamicPostHogProvider>
|
||||
<DynamicPostHogProvider>{Hydrated}</DynamicPostHogProvider>
|
||||
</DynamicIntercomProvider>
|
||||
</DynamicHelpscoutProvider>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user