# useQuery()

> Fetch data with the classic trpc.procedure.useQuery() hook, its tRPC-specific options and streaming

From https://trpc.io/docs/client/react/useQuery

> [!WARNING] Deprecated
> The classic React Query integration (`@trpc/react-query`) only gets bug fixes, and will be removed in the next major version of tRPC. New projects should use the [TanStack React Query integration](https://trpc.io/docs/client/tanstack-react-query) (`@trpc/tanstack-react-query`). To move an existing project, follow the [migration guide](https://trpc.io/docs/client/tanstack-react-query/migrating).


`useQuery` is the primary hook for data fetching, it works similarly to `@tanstack/react-query`'s `useQuery`, but with some `trpc` specific options and additional features like streaming.

> [!NOTE]
> For in-depth information about options and usage patterns, refer to the TanStack Query docs on [queries](https://tanstack.com/query/v5/docs/framework/react/guides/queries).


## Signature

```tsx no-check
declare function useQuery(
  input: TInput | SkipToken,
  opts?: UseTRPCQueryOptions,
): void;

interface UseTRPCQueryOptions
  extends UseQueryOptions {
  trpc: {
    ssr?: boolean;
    abortOnUnmount?: boolean;
    context?: Record<string, unknown>;
  }
}
```

Since `UseTRPCQueryOptions` extends `@tanstack/react-query`'s `UseQueryOptions`, you can use any of their options here such as `enabled`, `refetchOnWindowFocus`, etc. We also have some `trpc` specific options that let you opt in or out of certain behaviors on a per-procedure level:

- **`trpc.ssr`:** If you have `ssr: true` in your [global config](https://trpc.io/docs/client/nextjs/pages-router/setup#ssr-boolean-default-false), you can set this to false to disable ssr for this particular query. _Note that this does not work the other way around, i.e., you can not enable ssr on a procedure if your global config is set to false._
- **`trpc.abortOnUnmount`:** Override the [global config](https://trpc.io/docs/client/nextjs/pages-router/setup#config-callback) and opt in or out of aborting queries on unmount.
- **`trpc.context`:** Add extra meta data that could be used in [Links](https://trpc.io/docs/client/links).

> [!TIP]
> If you need to set any options but don't want to pass any input, you can pass `undefined` instead.


You'll notice that you get autocompletion on the `input` based on what you have set in your `input` schema on your backend.

## Example usage

<details>
<summary>Backend code</summary>

```tsx no-check title="server/routers/_app.ts"
import { initTRPC } from '@trpc/server';
import { z } from 'zod';

export const t = initTRPC.create();

export const appRouter = t.router({
  // Create procedure at path 'hello'
  hello: t.procedure
    // using zod schema to validate and infer input values
    .input(
      z
        .object({
          text: z.string().nullish(),
        })
        .nullish(),
    )
    .query((opts) => {
      return {
        greeting: `hello ${opts.input?.text ?? 'world'}`,
      };
    }),
});

export type AppRouter = typeof appRouter;
```

</details>

```tsx no-check title="components/MyComponent.tsx"
import { trpc } from '../utils/trpc';

export function MyComponent() {
  // input is optional, so we don't have to pass second argument
  const helloNoArgs = trpc.hello.useQuery();
  const helloWithArgs = trpc.hello.useQuery({ text: 'client' });

  return (
    <div>
      <h1>Hello World Example</h1>
      <ul>
        <li>
          helloNoArgs ({helloNoArgs.status}):{' '}
          <pre>{JSON.stringify(helloNoArgs.data, null, 2)}</pre>
        </li>
        <li>
          helloWithArgs ({helloWithArgs.status}):{' '}
          <pre>{JSON.stringify(helloWithArgs.data, null, 2)}</pre>
        </li>
      </ul>
    </div>
  );
}
```

## Streaming responses using async generators

> [!NOTE] Info
> Since v11 we now support streaming queries when using the [`httpBatchStreamLink`](https://trpc.io/docs/client/links/httpBatchStreamLink#generators).


When returning an async generator in a query, you will:

- Get the results of the iterator in the `data`-property **as an array** which updates as the response comes in
- The `status` will be `success` as soon as the first chunk is received.
- The `fetchStatus` property which will be `fetching` until the last chunk is received.

### Example

```tsx no-check title="server/routers/_app.ts"
import { initTRPC } from '@trpc/server';

const t = initTRPC.create();

const appRouter = t.router({
  iterable: t.procedure.query(async function* () {
    for (let i = 0; i < 3; i++) {
      await new Promise((resolve) => setTimeout(resolve, 500));
      yield i;
    }
  }),
});

export type AppRouter = typeof appRouter;
```

```tsx no-check title="components/MyComponent.tsx"
import React, { Fragment } from 'react';
import { trpc } from '../utils/trpc';

export function MyComponent() {
  const result = trpc.iterable.useQuery();

  return (
    <div>
      {result.data?.map((chunk, index) => (
        <Fragment key={index}>{chunk}</Fragment>
      ))}
    </div>
  );
}
```

`result` properties while streaming:

| `status`    | `fetchStatus` | `data`      |
| ----------- | ------------- | ----------- |
| `'pending'` | `'fetching'`  | `undefined` |
| `'success'` | `'fetching'`  | `[]`        |
| `'success'` | `'fetching'`  | `[0]`       |
| `'success'` | `'fetching'`  | `[0, 1]`    |
| `'success'` | `'fetching'`  | `[0, 1, 2]` |
| `'success'` | `'idle'`      | `[0, 1, 2]` |
