I’m trying to understand how to use the @tanstack/react-query
integration for tRPC
when I have conditional fetches that have required parameters.
For example, say I have this backend:
// Backend
export const t = initTRPC.create();
export const appRouter = t.router({
hello: t.procedure.input(
z.object({ text: z.string() })
).query((opts) => {
return {
greeting: `hello ${opts.input.text}`,
};
}),
});
Note that the text
parameter is required.
Now let’s say I have this frontend:
// Frontend
export const trpc = createTRPCReact<typeof appRouter>();
function MyComponent() {
const [text, setText] = useState<string | null>(null)
const {data: helloData} = trpc.hello.useQuery({ text }) // type error
return <>
<div>{helloData.greeting}</div>
<button onClick={() => setText('a')}>a</button>
<button onClick={() => setText('b')}>b</button>
<button onClick={() => setText(null)}>none</button>
</>
}
Here text
starts as null
, and so I cannot call fetch the trpc.hello
query until it has a value. So Typescript rightly complains:
Type 'string | null' is not assignable to type 'string'.
Type 'null' is not assignable to type 'string'.(2322)
So how to do I run this query conditionally?
I can’t conditionally run the query:
if (text !== null) trpc.hello.useQuery({ text }) // breaks rules of hooks
Due to the rules of hooks.
And this this:
const { data: helloData } = trpc.hello.useQuery(
{ text }, // type error, but works
{ enabled: text !== null }
)
Works at runtime, but the Typescript error is still there since it can’t really know that the object is expected to be invalid when it won’t be used.
So what is the right way to conditionally fetch a tRPC useQuery
?
Full code with type error in the typescript playground
It’s worth noting that tRPC v11 has a new feature for this: https://trpc.io/docs/client/react/disabling-queries
But I’m stuck on v10 for the time being due to other dependencies which are not yet compatible.
2
Answers
I see two ways to solve this:
The first one is to use
useQuery
with an activation condition:The second one is to use
useUtils
:see: https://trpc.io/docs/v10/client/react/useUtils
useQuery
is your go-to for managing data fetching with React Query. It takes care of things like keeping data fresh and updating automatically.useUtils
lets you take the wheel on data fetching. This is handy when you want to trigger data updates based on user actions, like button clicks, instead of just when a component loads.for v10, you can use the bang operator:
or write your schema in the backend so that it also accepts
null
, but then throws an error.The best thing of course is to update to v11 and use the
skipToken
, but you already know that 🙂