禁用/暂停查询

如果您希望禁用查询自动运行,可以使用 enabled = false 选项。 enabled 选项也接受返回布尔值的回调。

enabledfalse

  • 如果查询有缓存数据,则查询将在 status === 'success'isSuccess 状态下初始化。
  • 如果查询没有缓存数据,则查询将以 status === 'pending'fetchStatus === 'idle' 状态启动。
  • 查询不会在挂载时自动获取。
  • 查询不会在后台自动重新获取。
  • 查询将忽略查询客户端 invalidateQueriesrefetchQueries 调用,这些调用通常会导致查询重新获取。
  • injectQuery 返回的 refetch 可用于手动触发查询以进行获取。但是,它不适用于 skipToken

TypeScript 用户可能更喜欢使用 skipToken 作为 enabled = false 的替代方案。

angular-ts
@Component({
  selector: 'todos',
  template: `<div>
    <button (click)="query.refetch()">Fetch Todos</button>

    @if (query.data()) {
      <ul>
        @for (todo of query.data(); track todo.id) {
          <li>{{ todo.title }}</li>
        }
      </ul>
    } @else {
      @if (query.isError()) {
        <span>Error: {{ query.error().message }}</span>
      } @else if (query.isLoading()) {
        <span>Loading...</span>
      } @else if (!query.isLoading() && !query.isError()) {
        <span>Not ready ...</span>
      }
    }

    <div>{{ query.isLoading() ? 'Fetching...' : '' }}</div>
  </div>`,
})
export class TodosComponent {
  query = injectQuery(() => ({
    queryKey: ['todos'],
    queryFn: fetchTodoList,
    enabled: false,
  }))
}
@Component({
  selector: 'todos',
  template: `<div>
    <button (click)="query.refetch()">Fetch Todos</button>

    @if (query.data()) {
      <ul>
        @for (todo of query.data(); track todo.id) {
          <li>{{ todo.title }}</li>
        }
      </ul>
    } @else {
      @if (query.isError()) {
        <span>Error: {{ query.error().message }}</span>
      } @else if (query.isLoading()) {
        <span>Loading...</span>
      } @else if (!query.isLoading() && !query.isError()) {
        <span>Not ready ...</span>
      }
    }

    <div>{{ query.isLoading() ? 'Fetching...' : '' }}</div>
  </div>`,
})
export class TodosComponent {
  query = injectQuery(() => ({
    queryKey: ['todos'],
    queryFn: fetchTodoList,
    enabled: false,
  }))
}

永久禁用查询会选择退出 TanStack Query 提供的许多强大功能(例如后台重新获取),而且这不是惯用的方式。它将您从声明式方法(定义查询应何时运行的依赖项)带到命令式模式(每当我点击此处时获取)。也不可能将参数传递给 refetch。通常,您想要的只是一个延迟初始获取的惰性查询

懒加载查询

enabled 选项不仅可以用于永久禁用查询,还可以用于稍后启用/禁用它。一个很好的例子是过滤器表单,您只想在用户输入过滤器值后才触发第一个请求

angular-ts
@Component({
  selector: 'todos',
  template: `
    <div>
      // 🚀 applying the filter will enable and execute the query
      <filters-form onApply="filter.set" />
      <todos-table data="query.data()" />
    </div>
  `,
})
export class TodosComponent {
  filter = signal('')

  todosQuery = injectQuery(() => ({
    queryKey: ['todos', this.filter()],
    queryFn: () => fetchTodos(this.filter()),
    enabled: !!this.filter(),
  }))
}
@Component({
  selector: 'todos',
  template: `
    <div>
      // 🚀 applying the filter will enable and execute the query
      <filters-form onApply="filter.set" />
      <todos-table data="query.data()" />
    </div>
  `,
})
export class TodosComponent {
  filter = signal('')

  todosQuery = injectQuery(() => ({
    queryKey: ['todos', this.filter()],
    queryFn: () => fetchTodos(this.filter()),
    enabled: !!this.filter(),
  }))
}

isLoading (之前:isInitialLoading)

惰性查询从一开始就处于 status: 'pending' 状态,因为 pending 意味着当前没有数据。这在技术上是正确的,但是,由于我们目前没有获取任何数据(因为查询未启用),这也意味着您可能无法使用此标志来显示加载指示器。

如果您正在使用禁用或惰性查询,则可以使用 isLoading 标志。它是一个从以下内容计算得出的派生标志

isPending && isFetching

因此,它仅在查询当前首次获取时为真。

使用 skipToken 安全地禁用查询

如果您正在使用 TypeScript,则可以使用 skipToken 来禁用查询。当您想要根据条件禁用查询,但仍然希望保持查询的类型安全时,这非常有用。

重要提示:来自 injectQueryrefetch 不适用于 skipToken。除此之外,skipToken 的工作方式与 enabled: false 相同。

angular-ts
import { skipToken, injectQuery } from '@tanstack/query-angular'

@Component({
  selector: 'todos',
  template: `
    <div>
      // 🚀 applying the filter will enable and execute the query
      <filters-form onApply="filter.set" />
      <todos-table data="query.data()" />
    </div>
  `,
})
export class TodosComponent {
  filter = signal('')

  todosQuery = injectQuery(() => ({
    queryKey: ['todos', this.filter()],
    queryFn: this.filter() ? () => fetchTodos(this.filter()) : skipToken,
  }))
}
import { skipToken, injectQuery } from '@tanstack/query-angular'

@Component({
  selector: 'todos',
  template: `
    <div>
      // 🚀 applying the filter will enable and execute the query
      <filters-form onApply="filter.set" />
      <todos-table data="query.data()" />
    </div>
  `,
})
export class TodosComponent {
  filter = signal('')

  todosQuery = injectQuery(() => ({
    queryKey: ['todos', this.filter()],
    queryFn: this.filter() ? () => fetchTodos(this.filter()) : skipToken,
  }))
}