reactjstypescriptreact-querytanstackreact-querytrpc

Conditional tRPC v10 fetch with useQuery and required parameters


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.


Solution

  • for v10, you can use the bang operator:

    const { data: helloData } = trpc.hello.useQuery(
      { text: text! },
      { enabled: text !== null }
    )
    

    or write your schema in the backend so that it also accepts null, but then throws an error.

    It's worth noting that tRPC v11 has a new feature for this: https://trpc.io/docs/client/react/disabling-queries

    The best thing of course is to update to v11 and use the skipToken, but you already know that :)