查询
查询基础
查询是对异步数据源的一种声明式依赖,它与一个唯一键相关联。查询可用于任何基于 Promise 的方法(包括 GET 和 POST 方法)以从服务器拉取数据。如果你的方法会修改服务器上的数据,我们建议改用修改。
要在组件或服务中订阅一个查询,请调用 injectQuery,至少传入以下两项参数:
- 该查询的唯一键
- 一个返回 Promise 或 Observable 的函数,该函数:
- 成功解析出数据,或
- 抛出错误
TypeScript
1import { injectQuery } from '@tanstack/angular-query-experimental'2 3export class TodosComponent {4 readonly todosQuery = injectQuery(() => ({5 queryKey: ['todos'],6 queryFn: fetchTodoList,7 }))8}你提供的唯一键会在内部用于重新拉取、缓存以及在整个应用中共享该查询。
injectQuery 返回的查询结果对象包含了你在模板渲染及其他数据使用场景中所需的所有查询信息:
TypeScript
1todosQuery = injectQuery(() => ({2 queryKey: ['todos'],3 queryFn: fetchTodoList,4}))result 对象包含若干关键状态,你必须了解这些状态才能高效使用。在任意时刻,查询仅可能处于以下状态之一:
isPending或status === 'pending'—— 查询尚无数据isError或status === 'error'—— 查询发生错误isSuccess或status === 'success'—— 查询成功,数据可用
除上述主要状态外,还可根据查询当前所处状态获取更多信息:
error—— 若查询处于isError状态,则可通过error属性获取错误信息。data—— 若查询处于isSuccess状态,则可通过data属性获取数据。isFetching—— 在任何状态下,只要查询正在拉取(包括后台重新拉取),isFetching均为true。
对于大多数查询,通常只需依次检查 isPending 状态、再检查 isError 状态,最后即可默认数据已就绪并渲染成功状态:
angular-ts
1@Component({2 selector: 'todos',3 template: `4 @if (todosQuery.isPending()) {5 <span>Loading...</span>6 } @else if (todosQuery.isError()) {7 <span>Error: {{ todosQuery.error()?.message }}</span>8 } @else {9 <!-- We can assume by this point that status === 'success' -->10 @for (todo of todosQuery.data(); track todo.id) {11 <li>{{ todo.title }}</li>12 } @empty {13 <li>No todos found</li>14 }15 }16 `,17})18export class PostsComponent {19 readonly todosQuery = injectQuery(() => ({20 queryKey: ['todos'],21 queryFn: fetchTodoList,22 }))23}若你不习惯使用布尔值判断,也可直接使用 status 状态:
angular-ts
1@Component({2 selector: 'todos',3 template: `4 @switch (todosQuery.status()) {5 @case ('pending') {6 <span>Loading...</span>7 }8 @case ('error') {9 <span>Error: {{ todosQuery.error()?.message }}</span>10 }11 <!-- also status === 'success', but "else" logic works, too -->12 @default {13 <ul>14 @for (todo of todosQuery.data(); track todo.id) {15 <li>{{ todo.title }}</li>16 } @empty {17 <li>No todos found</li>18 }19 </ul>20 }21 }22 `,23})24class TodosComponent {}若你在访问 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的信息:它是否正在运行?