Query Basics #
A query is a declarative dependency on an asynchronous source of data that is tied to a unique key. A query can be used with any Promise based method (including GET and POST methods) to fetch data from a server. If your method modifies data on the server, we recommend using Mutations instead.
To subscribe to a query in your components or custom hooks, call the useQuery
hook with at least:
- A unique key for the query
- A function that returns a promise that:
- Resolves the data, or
- Throws an error
1import { useQuery } from '@tanstack/react-query'
2
3function App() {
4 const info = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList })
5}
The unique key you provide is used internally for refetching, caching, and sharing your queries throughout your application.
The query result returned by useQuery
contains all of the information about the query that you'll need for templating and any other usage of the data:
1const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList })
The result
object contains a few very important states you'll need to be aware of to be productive. A query can only be in one of the following states at any given moment:
isPending
orstatus === 'pending'
- The query has no data yetisError
orstatus === 'error'
- The query encountered an errorisSuccess
orstatus === 'success'
- The query was successful and data is available
Beyond those primary states, more information is available depending on the state of the query:
error
- If the query is in anisError
state, the error is available via theerror
property.data
- If the query is in anisSuccess
state, the data is available via thedata
property.isFetching
- In any state, if the query is fetching at any time (including background refetching)isFetching
will betrue
.
For most queries, it's usually sufficient to check for the isPending
state, then the isError
state, then finally, assume that the data is available and render the successful state:
1function Todos() {
2 const { isPending, isError, data, error } = useQuery({
3 queryKey: ['todos'],
4 queryFn: fetchTodoList,
5 })
6
7 if (isPending) {
8 return <span>Loading...</span>
9 }
10
11 if (isError) {
12 return <span>Error: {error.message}</span>
13 }
14
15 // We can assume by this point that `isSuccess === true`
16 return (
17 <ul>
18 {data.map((todo) => (
19 <li key={todo.id}>{todo.title}</li>
20 ))}
21 </ul>
22 )
23}
If booleans aren't your thing, you can always use the status
state as well:
1function Todos() {
2 const { status, data, error } = useQuery({
3 queryKey: ['todos'],
4 queryFn: fetchTodoList,
5 })
6
7 if (status === 'pending') {
8 return <span>Loading...</span>
9 }
10
11 if (status === 'error') {
12 return <span>Error: {error.message}</span>
13 }
14
15 // also status === 'success', but "else" logic works, too
16 return (
17 <ul>
18 {data.map((todo) => (
19 <li key={todo.id}>{todo.title}</li>
20 ))}
21 </ul>
22 )
23}
TypeScript will also narrow the type of data
correctly if you've checked for pending
and error
before accessing it.
FetchStatus #
In addition to the status
field, you will also get an additional fetchStatus
property with the following options:
fetchStatus === 'fetching'
- The query is currently fetching.fetchStatus === 'paused'
- The query wanted to fetch, but it is paused. Read more about this in the Network Mode guide.fetchStatus === 'idle'
- The query is not doing anything at the moment.
Why two different states? #
Background refetches and stale-while-revalidate logic make all combinations for status
and fetchStatus
possible. For example:
- a query in
success
status will usually be inidle
fetchStatus, but it could also be infetching
if a background refetch is happening. - a query that mounts and has no data will usually be in
pending
status andfetching
fetchStatus, but it could also bepaused
if there is no network connection.
So keep in mind that a query can be in pending
state without actually fetching data. As a rule of thumb:
- The
status
gives information about thedata
: Do we have any or not? - The
fetchStatus
gives information about thequeryFn
: Is it running or not?
Further Reading #
For an alternative way of performing status checks, have a look at the Community Resources.