查询
查询基础
查询是对异步数据源的一种声明式依赖,它与一个唯一键相关联。查询可用于任何基于 Promise 的方法(包括 GET 和 POST 方法)来从服务器拉取数据。如果你的方法会修改服务器上的数据,我们建议改用修改。
要在组件或自定义 Hook 中订阅某个查询,请至少传入以下参数调用 useQuery Hook:
- 该查询的唯一键
- 一个返回 Promise 的函数,该 Promise:
- 成功解析出数据,或
- 抛出错误
TypeScript
1import { useQuery } from '@tanstack/preact-query'2 3function App() {4 const info = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList })5}你提供的唯一键会在内部用于重新拉取、缓存以及在整个应用中共享该查询。
useQuery 返回的查询结果对象包含了你在模板渲染及数据其他用途中所需的所有查询信息:
TypeScript
1const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList })result 对象包含若干关键状态,你需要了解这些状态才能高效使用。在任意时刻,查询只能处于以下状态之一:
isPending或status === 'pending'— 查询尚无数据isError或status === 'error'— 查询发生错误isSuccess或status === 'success'— 查询成功,数据已就绪
除上述主要状态外,还可根据查询当前所处状态获取更多信息:
error— 若查询处于isError状态,则可通过error属性获取错误信息。data— 若查询处于isSuccess状态,则可通过data属性获取数据。isFetching— 在任意状态下,只要查询正在拉取(包括后台拉取),isFetching均为true。
对于大多数查询,通常只需依次检查 isPending 状态、接着检查 isError 状态,最后即可假定数据已就绪并渲染成功状态:
TypeScript
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}若你不习惯使用布尔值判断,也可直接使用 status 状态:
TypeScript
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, too16 return (17 <ul>18 {data.map((todo) => (19 <li key={todo.id}>{todo.title}</li>20 ))}21 </ul>22 )23}若你在访问 data 前已检查过 pending 和 error,TypeScript 也会正确收窄 data 的类型。
fetchStatus
除 status 字段外,你还将获得一个额外的 fetchStatus 属性,其取值如下:
fetchStatus === 'fetching'— 查询当前正在拉取。fetchStatus === 'paused'— 查询本应拉取,但已被暂停。更多细节请参阅网络模式指南。fetchStatus === 'idle'— 查询当前未执行任何操作。
为何需要两种不同状态?
后台拉取与“过期时验证”(stale-while-revalidate)逻辑使得 status 和 fetchStatus 的所有组合均可能出现。例如:
- 处于
success状态的查询通常对应idlefetchStatus,但如果此时正进行后台拉取,则也可能为fetching。 - 一个挂载时无数据的查询通常处于
pending状态和fetchingfetchStatus,但如果当前无网络连接,则可能为paused。
因此请谨记:查询处于 pending 状态并不代表它正在拉取数据。经验法则是:
status表示data的可用性:我们是否有数据?fetchStatus表示queryFn的运行状态:它是否正在运行?
延伸阅读
如需了解执行状态检查的另一种方式,请参阅TkDodo 撰写的这篇文章。