# Reading queries

> useQuery returns a stable thenable and the query's state; read it with use() under Suspense, switch on its status, or pass it down to a child.

Components read queries with `useQuery`, passing the factory and the handle the loader returned:

```ts
const [postThenable, postState] = useQuery(factory, handle, options);
const post = use(postThenable);
```

`postThenable` is a stable `Thenable<Data>` owned by the cache: a `Promise` that also carries `status`, `value` and `reason`, the fields React's [`use()`](https://react.dev/reference/react/use) reads. Read it with `use()` on its own line. When the cache already has the data, the thenable is fulfilled and `use()` returns it synchronously; otherwise `use()` suspends until it lands.

`useQuery` returns a thenable for every handle. A handle from `swr` or `revalidate` had its data loaded before the route rendered, so `use()` doesn't suspend on it. If the cache dropped the data since (garbage collection, `resetOne`, `removeOne`), `use()` suspends while the query refetches. See [Handles](https://raf-query.katt.dev/docs/handles.md#reading-a-handle).

```tsx
function PostPage() {
	const loaderData = Route.useLoaderData();
	// `post` came from `swr`, `comments` from `prefetch`.
	const [postThenable, postState] = useQuery(postQuery, loaderData.post);
	const post = use(postThenable);

	return (
		<article>
			<h1>{post.title}</h1>
			<button
				disabled={postState.isFetching}
				onClick={() => startTransition(() => postState.refetch())}
			>
				Refresh
			</button>
			<p>{post.body}</p>
			<Suspense fallback={<CommentsSkeleton />}>
				<Comments handle={loaderData.comments} />
			</Suspense>
		</article>
	);
}
```

`options` takes [`whilePending`](https://raf-query.katt.dev/docs/url-state-and-pagination.md). There is no option to change the input: the handle decides what is read. Settings such as polling belong to the query, as [`meta`](https://raf-query.katt.dev/docs/query-meta.md) in its factory.

## State

| Field               | Meaning                                                                                                    |
| ------------------- | ---------------------------------------------------------------------------------------------------------- |
| `isPending`         | No data yet for the handle's input; `use()` on the thenable will suspend                                   |
| `isPrevious`        | The thenable holds the previous handle's data while this handle's query loads (`whilePending: "previous"`) |
| `isFetching`        | A request is in flight: first load, new input, or background refetch                                       |
| `isStale`           | Data is older than `staleTime`, or was invalidated                                                         |
| `error`             | The last request's error while it's the latest outcome                                                     |
| `updatedAt`         | When the handle's data was fetched; `0` without data                                                       |
| `queryKey`, `input` | The handle's key and input                                                                                 |
| `hash`              | Stable string form of the handle's key, for `key` props on Suspense boundaries                             |
| `refetch()`         | Refetch now. Returns a promise, so it can be awaited inside a transition or action                         |

Paged factories read with `useInfiniteQuery`, whose state adds `fetchNextPage()`, `fetchPreviousPage()`, `hasNextPage`, `hasPreviousPage`, `isFetchingNextPage` and `isFetchingPreviousPage`. See [Infinite queries](https://raf-query.katt.dev/docs/infinite-queries.md).

## Updates never suspend

When the cache updates — refetch, invalidation, `setData` — the hook returns a new, fulfilled thenable and the component re-renders without suspending. New data is structurally shared with the old: a refetch that returns equal data keeps the same thenable and the same objects, so memoized children don't re-render. See [Render optimizations](https://raf-query.katt.dev/docs/render-optimizations.md).

## Errors

When the **first** load fails, the thenable rejects and `use()` throws to the nearest error boundary. A failed **background** refetch doesn't throw: the old data stays on screen and the state's `error` holds the error, so the component can show it next to the data. [Retries](https://raf-query.katt.dev/docs/retries.md) has a demo of both.

Before resetting the error boundary, call `resetOne(qc, factory, input)`, so the query loads again instead of throwing the same error.

## Passing thenables down

A component can call the hook with a prefetched handle and hand the thenable to a child, so only the child suspends:

```tsx
const [postThenable] = useQuery(postQuery, loaderData.post); // from `prefetch`
return (
	<Suspense fallback={<Spinner />}>
		<PostBody post={postThenable} />
	</Suspense>
);
```

The component that calls `useQuery` re-renders when its thenable changes, and when a state field it read changes, such as `isFetching` during a background refetch. A parent that should stay put can pass the handle down instead, so only the child reads the query. See [Tracked state](https://raf-query.katt.dev/docs/render-optimizations.md#tracked-state).

Because `use()` can be called conditionally, a component can also decide **whether** to read:

```tsx
function Details(props: { open: boolean; details: Promise<Details> }) {
	if (!props.open) return null;
	const details = use(props.details);
	return <DetailsTable details={details} />;
}
```

## No refetch on mount

`useQuery` never refetches stale data on mount: whatever started the query decides. Stale data refetches when a loader or server component starts the query again, when it's [invalidated](https://raf-query.katt.dev/docs/query-invalidation.md) (a reader that mounts after an invalidation refetches it), on `refetch()`, and with the client's features: [window focus](https://raf-query.katt.dev/docs/window-focus-refetching.md) and reconnect refetching, and [polling](https://raf-query.katt.dev/docs/polling.md). A reader only fetches on its own when the query has no data, which is a [waterfall](https://raf-query.katt.dev/docs/request-waterfalls.md).

That means rendering the same handle in many components is free: they share one entry and one request. See [Background fetching indicators](https://raf-query.katt.dev/docs/background-fetching-indicators.md) to show when a refetch is running.
