Queries
Query Basics
查询(Query)是对异步数据源的声明性依赖,它与一个唯一的键(unique key)相关联。可以使用查询与任何基于 Promise 的方法(包括 GET 和 POST 方法)一起,从服务器获取数据。如果你的方法在服务器上修改数据,我们建议使用 Mutations(变更)。
要在组件或自定义钩子中订阅查询,可以调用 useQuery
钩子,至少需要提供以下参数:
- 查询的唯一键(key)
- 一个返回 Promise 的函数,该函数可能:
- 解析数据,或者
- 抛出错误
import { useQuery } from '@tanstack/react-query';
function App() {
const info = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList })
}
你提供的唯一键(key)在内部用于查询的重新获取(refetching)、缓存(caching)和在应用程序中共享查询(sharing)。
useQuery 返回的查询结果对象包含了关于查询的所有信息,你可以根据这些信息进行模板化和其他数据使用方式:
const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList })
result
结果对象包含了一些非常重要的状态,你需要了解这些状态以提高工作效率。查询在任何给定的时刻只能处于以下状态之一:
isLoading
或status === 'loading'
- 查询尚未有数据isError
或status === 'error'
- 查询遇到了错误isSuccess
或 status ==='success'
- 查询成功并且数据可用 除了这些主要的状态之外,根据查询的状态还可以获取更多的信息:
error
- 如果查询处于 isError
状态,可以通过 error
属性获取错误信息。
data
- 如果查询处于 isSuccess
状态,可以通过 data
属性获取数据。
对于大多数查询来说,通常只需要检查 isLoading 状态,然后检查 isError 状态,最后可以假设数据可用并渲染成功的状态:
function Todos() {
const { isLoading, isError, data, error } = useQuery({
queryKey: ['todos'],
queryFn: fetchTodoList,
})
if (isLoading) {
return <span>Loading...</span>
}
if (isError) {
return <span>Error: {error.message}</span>
}
// We can assume by this point that `isSuccess === true`
return (
<ul>
{data.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
)
}
如果布尔值不符合你的需求,也可以使用 status 状态: if (status === 'loading')
,if (status === 'error')
如果你在访问它之前检查了加载和错误,TypeScript也会正确地缩小数据的类型。
FetchStatus
除了状态字段 status,你还将获得一个额外的 fetchStatus
属性,它具有以下选项:
fetchStatus === 'fetching'
- 查询正在获取数据。
fetchStatus === 'paused'
- 查询想要获取数据,但是被暂停了。在 Network Mode 指南中可以了解更多信息。
fetchStatus === 'idle'
- 查询当前没有任何操作。
为什么有两个不同的状态? 后台重新获取和过期-同时重新验证(stale-while-revalidate)的逻辑使得 status 和 fetchStatus 可能出现各种组合。例如:
- 成功状态的查询通常会处于
idle
的 fetchStatus,但如果正在进行后台重新获取,则可能处于fetching
状态。 - 当查询挂载且没有数据时,通常会处于
loading
状态和fetching
的 fetchStatus,但如果没有网络连接,则可能被paused
。
因此,请记住,查询可能处于 loading 状态,但实际上并未获取数据。作为一个经验法则:
status
提供关于 data
的信息:我们是否有数据?
fetchStatus
提供关于 queryFn
的信息:它是否正在运行?