shared useTRPCClient hook conversion to v11

In our mono repo, we have 30 or so MFEs which all use the same TRPC client setup. So, we abstracted the inner workings of getting the TRPC client set up away in a different package as a hook. Now, I'm converting the code to v11, and I'm running into deprecation warnings and typescript errors. Our hook looks like this:
import { useState } from 'react';

import { createWSClient, getFetch, httpLink, splitLink, wsLink } from '@trpc/client';
import type { TRPCClient, TRPCLink } from '@trpc/client'; // [1] TRPCClient no longer exported

import type { AnyRouter } from '@trpc/server'; // [2] AnyRouter deprecated

type TRPC<TRouter extends AnyRouter> = {
createClient: (opts: { links: TRPCLink<TRouter>[] }) => TRPCClient<TRouter>;
};

export const useTRPCClient = <TRouter extends AnyRouter>(trpc: TRPC<TRouter>, url: string, wsUrl?: string) => {
const [trpcClient] = useState(() => {
const http = httpLink({
url,
fetch: async (input, init) => {
const fetch = getFetch();
return fetch(input, { ...init, credentials: 'include' });
},
headers: () => {
const originURL = window.location.href;
return {
'origin-url': originURL,
};
},
});

const wsClient = wsUrl ? createWSClient({ url: wsUrl }) : null;
const ws = wsClient ? wsLink({ client: wsClient }) : null;

return trpc.createClient({
links: ws
? [
splitLink({
condition: (op) => op.type === 'subscription',
true: ws,
false: http,
}),
]
: [http],
});
});

return trpcClient;
};
import { useState } from 'react';

import { createWSClient, getFetch, httpLink, splitLink, wsLink } from '@trpc/client';
import type { TRPCClient, TRPCLink } from '@trpc/client'; // [1] TRPCClient no longer exported

import type { AnyRouter } from '@trpc/server'; // [2] AnyRouter deprecated

type TRPC<TRouter extends AnyRouter> = {
createClient: (opts: { links: TRPCLink<TRouter>[] }) => TRPCClient<TRouter>;
};

export const useTRPCClient = <TRouter extends AnyRouter>(trpc: TRPC<TRouter>, url: string, wsUrl?: string) => {
const [trpcClient] = useState(() => {
const http = httpLink({
url,
fetch: async (input, init) => {
const fetch = getFetch();
return fetch(input, { ...init, credentials: 'include' });
},
headers: () => {
const originURL = window.location.href;
return {
'origin-url': originURL,
};
},
});

const wsClient = wsUrl ? createWSClient({ url: wsUrl }) : null;
const ws = wsClient ? wsLink({ client: wsClient }) : null;

return trpc.createClient({
links: ws
? [
splitLink({
condition: (op) => op.type === 'subscription',
true: ws,
false: http,
}),
]
: [http],
});
});

return trpcClient;
};
Issue 1: TRPCClient type is no longer exported from @trpc/client. I assume we can replace it with createClient: (opts: { links: TRPCLink<TRouter>[] }) => ReturnType<typeof createTRPCClient>; correct? Issue 2: the AnyRouter type deprecation, how can that be resolved?
B
BeBoRE47d ago
Why not use @trpc/react?
W
wleistra47d ago
We do! The prop trpc is coming from createReactRouter<AppRouter> like this
import type { AppRouter } from 'mfe-middleware';

import type { inferReactQueryProcedureOptions } from '@trpc/react-query';
import { createTRPCReact } from '@trpc/react-query';
import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server';

/* eslint-disable import/no-unused-modules */
export type ReactQueryOptions = inferReactQueryProcedureOptions<AppRouter>;
export type RouterInputs = inferRouterInputs<AppRouter>;
export type RouterOutputs = inferRouterOutputs<AppRouter>;
/* eslint-enable import/no-unused-modules */

export const trpc = createTRPCReact<AppRouter>();
import type { AppRouter } from 'mfe-middleware';

import type { inferReactQueryProcedureOptions } from '@trpc/react-query';
import { createTRPCReact } from '@trpc/react-query';
import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server';

/* eslint-disable import/no-unused-modules */
export type ReactQueryOptions = inferReactQueryProcedureOptions<AppRouter>;
export type RouterInputs = inferRouterInputs<AppRouter>;
export type RouterOutputs = inferRouterOutputs<AppRouter>;
/* eslint-enable import/no-unused-modules */

export const trpc = createTRPCReact<AppRouter>();
And this is how we put it all together
import type { ReactNode } from 'react';
import React from 'react';

import { createQueryClient, useTRPCClient } from '@company/utils';
import { QueryClientProvider } from '@tanstack/react-query';

import { trpc } from './trpc';

const queryClient = createQueryClient();

interface MFEQueryProviderProps {
children: ReactNode;
}

export const MFEQueryProvider = ({ children }: MFEQueryProviderProps) => {
const trpcClient = useTRPCClient(trpc, process.env.API_URL ?? '');

return (
<trpc.Provider client={trpcClient} queryClient={queryClient}>
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
</trpc.Provider>
);
};
import type { ReactNode } from 'react';
import React from 'react';

import { createQueryClient, useTRPCClient } from '@company/utils';
import { QueryClientProvider } from '@tanstack/react-query';

import { trpc } from './trpc';

const queryClient = createQueryClient();

interface MFEQueryProviderProps {
children: ReactNode;
}

export const MFEQueryProvider = ({ children }: MFEQueryProviderProps) => {
const trpcClient = useTRPCClient(trpc, process.env.API_URL ?? '');

return (
<trpc.Provider client={trpcClient} queryClient={queryClient}>
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
</trpc.Provider>
);
};
If there is a more efficient/better practice to achieve the sharing of the same client setup across all our Frontends without duplicating the code I'm all ears too... So far we successfully used this way with trpc 10
AK
Alex / KATT 🐱47d ago
there should be comments on all deprecations feel free to make a pr on things that we might've removed we have started being explicit about what we import + added smurfing(https://blog.codinghorror.com/new-programming-jargon/#21) on most variables/types if you need consulting for the migration email you can email sales@trpc.io
W
wleistra46d ago
This is the information vscode gives about the deprecation:
'AnyRouter' is deprecated.ts(6385)
index.d.ts(12, 4): The declaration was marked as deprecated here.
⚠ Error(TS6385) |
AnyRouter is deprecated.
(alias) type AnyRouter = Router<any, any>
import AnyRouter
'AnyRouter' is deprecated.ts(6385)
index.d.ts(12, 4): The declaration was marked as deprecated here.
⚠ Error(TS6385) |
AnyRouter is deprecated.
(alias) type AnyRouter = Router<any, any>
import AnyRouter
Maybe a comment was missed along the way? When trying to use Router<any, any> directly it says Router is not exported from @trpc/server I worked around the issue by not returning the createClient but by returning the links instead. and have the createClient in the MFE's own useState.
W
wleistra46d ago
Thanks @Alex / KATT 🐱 for the extra details on the comments.
More Posts
Question: Is there a way to have a base interface for Trpc router?Hi, So I am trying to see if there is way to keep methods inside trpc routes consistent, Like in capersistedQueries & indexedDbWould like to know if someone else has tried out the feature and/if got it work, I'm trying to recrePublic and Private procedures Not working with Clerk and PrismaI have initialized a create-t3-app. I want to use clerk as my auth provider. I have ran into a problProperly handle unifying interfaces from tRPC call?I have two types of objects in my database, `quests` and `tasks`, which share several common propertType 'QueryClient' is missing the following properties from type 'QueryClient': queryCache, mutationI'm getting this error: > Type 'QueryClient' is missing the following properties from type 'QueryClHow to properly handle Prima selects/includes with tRPC?Hello, my understanding of optimizing procedures to be the most efficient would be to enable one proonSuccess with createTRPCProxyClientWhat is the best way to setup onSuccess with createTRPCProxyClient?trpcNext from client for testingHi guys, I have created a client that uses a mock database for testing. Can I create a context and tMissing content type header for mutations leads to 405Im migrating my app from Next Pages Router to App Router. I implemented the new trpc wrapper as explIs there any way to temporarily disable mutations?My goal is to move into a read-only mode temporarily. I'm thinking anything could be fine as a shoAfter upgrading to 11.0.0-next-beta.300, every request throws zod errorI didn't do anything but upgrading the trpc, and the error throws: ```json {"issues":[{"code":"invaSetting up tRPC for next.js with edge AND serverless functionstldr: I am trying to build an app that uses both edge AND serverless functions by creating separate Hello i am using trpc open api but there is an issue regarding using z.optional() however in the libHello i am using trpc open api but there is an issue regarding using z.optional() however in the libCreateCaller with React-queryHey guys. Is it possible to combine createCaller approach with React-query? I figured out that reactBeginner: form field error handling ?hey guys, I have a question regarding error handling with trpc. How could I specify a form field iZod.enum makes my tRPC explodeI'm having an issue with what appears to be circular dependencies. My problem is that I'm not sure wReact type errors because of backendHello, I'm using tRPC in React and it's working fine generally. However, WebPack always finds somethValue attached to all queriesIs it possible to add a value the all queries so its preset within every procedure call on the clienInvalidating query cache irrespective of query paramsHey is it possible to invalidate a query cache without providing parameters? I have a query for exaSentry integrationHello. I'm using trpc + fastify approach. I need a proper error loggin so I added fastify sentry, wh