禁用/暂停查询
如果你希望禁用某个查询的自动执行,可以使用 enabled = false 选项。enabled 选项还支持传入一个返回布尔值的回调函数。
当 enabled 为 false 时:
- 如果查询已有缓存数据,则查询将初始化为
status === 'success'或isSuccess状态。 - 如果查询没有缓存数据,则查询将从
status === 'pending'和fetchStatus === 'idle'状态开始。 - 查询不会在组件挂载时自动拉取。
- 查询不会在后台自动重新拉取。
- 查询将忽略查询客户端(QueryClient)的
invalidateQueries和refetchQueries调用(这些调用通常会触发查询的重新拉取)。 - 可通过
refetch(由injectQuery返回)手动触发查询拉取。但该方法不适用于skipToken。
使用 TypeScript 的用户可能更倾向于使用 skipToken 作为
enabled = false的替代方案。
1@Component({2 selector: 'todos',3 template: `<div>4 <button (click)="todosQuery.refetch()">Fetch Todos</button>5 6 @if (todosQuery.data()) {7 <ul>8 @for (todo of todosQuery.data(); track todo.id) {9 <li>{{ todo.title }}</li>10 }11 </ul>12 } @else {13 @if (todosQuery.isError()) {14 <span>Error: {{ todosQuery.error().message }}</span>15 } @else if (todosQuery.isLoading()) {16 <span>Loading...</span>17 } @else if (!todosQuery.isLoading() && !todosQuery.isError()) {18 <span>Not ready ...</span>19 }20 }21 22 <div>{{ todosQuery.isLoading() ? 'Fetching...' : '' }}</div>23 </div>`,24})25export class TodosComponent {26 readonly todosQuery = injectQuery(() => ({27 queryKey: ['todos'],28 queryFn: fetchTodoList,29 enabled: false,30 }))31}永久禁用查询会使你无法使用 TanStack Query 提供的许多优秀功能(例如后台重新拉取),而且这种做法也不符合其设计范式。它会迫使你从声明式方式(定义查询应在何时运行)转向命令式方式(点击此处时才拉取)。此外,你无法向 refetch 传递参数。很多时候,你真正需要的只是一个延迟查询(lazy query),即推迟首次拉取操作:
延迟查询(Lazy Queries)
enabled 选项不仅可以用于永久禁用查询,还可用于在后续某个时间点启用或禁用查询。一个典型示例是筛选表单:你仅希望在用户输入筛选值后才发起首次请求:
1@Component({2 selector: 'todos',3 template: `4 <div>5 // 🚀 applying the filter will enable and execute the query6 <filters-form onApply="filter.set" />7 <todos-table data="todosQuery.data()" />8 </div>9 `,10})11export class TodosComponent {12 filter = signal('')13 14 readonly todosQuery = injectQuery(() => ({15 queryKey: ['todos', this.filter()],16 queryFn: () => fetchTodos(this.filter()),17 enabled: !!this.filter(),18 }))19}isLoading(此前名为 isInitialLoading)
延迟查询从一开始便处于 status: 'pending' 状态,因为 pending 意味着尚无数据。这在技术上是正确的;但由于此时并未实际拉取任何数据(查询尚未 启用),因此你很可能无法利用此标志来显示加载指示器(loading spinner)。
如果你正在使用已禁用或延迟的查询,可改用 isLoading 标志。这是一个派生标志,其值根据以下条件计算得出:
isPending && isFetching
因此,仅当查询当前正进行首次拉取时,该标志才为 true。
使用 skipToken 类型安全地禁用查询
如果你正在使用 TypeScript,可通过 skipToken 来禁用查询。当你需要基于某个条件禁用查询、同时又希望保持类型安全时,这种方式非常有用。
重要提示:
refetch(由injectQuery返回)无法与skipToken配合使用。对使用skipToken的查询调用refetch()将导致Missing queryFn错误,因为此时不存在有效的查询函数可供执行。如需手动触发查询,请考虑改用enabled: false,它能确保refetch()正常工作。除这一限制外,skipToken的行为与enabled: false完全一致。
1import { skipToken, injectQuery } from '@tanstack/angular-query-experimental'2 3@Component({4 selector: 'todos',5 template: `6 <div>7 // 🚀 applying the filter will enable and execute the query8 <filters-form onApply="filter.set" />9 <todos-table data="todosQuery.data()" />10 </div>11 `,12})13export class TodosComponent {14 filter = signal('')15 16 readonly todosQuery = injectQuery(() => ({17 queryKey: ['todos', this.filter()],18 queryFn: this.filter() ? () => fetchTodos(this.filter()) : skipToken,19 }))20}