查询

查询基础知识

查询是对异步数据源的声明式依赖,它与一个唯一的键绑定。查询可以与任何基于 Promise 的方法(包括 GET 和 POST 方法)一起使用,以从服务器获取数据。如果你的方法修改了服务器上的数据,我们建议使用 突变 代替。

要在你的组件或服务中订阅查询,请调用 injectQuery,至少需要

  • 查询的唯一键
  • 一个返回 promise 或 observable 的函数,该函数
    • 解析数据,或
    • 抛出一个错误
ts
import { injectQuery } from '@tanstack/angular-query-experimental'

export class TodosComponent {
  info = injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodoList }))
}
import { injectQuery } from '@tanstack/angular-query-experimental'

export class TodosComponent {
  info = injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodoList }))
}

你提供的唯一键在内部用于重新获取、缓存以及在你的应用程序中共享你的查询。

injectQuery 返回的查询结果包含了关于查询的所有信息,你将需要在模板和任何其他数据使用场景中使用这些信息

ts
result = injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodoList }))
result = injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodoList }))

result 对象包含了一些非常重要的状态,你需要了解这些状态才能高效工作。一个查询在任何给定时刻只能处于以下状态之一

  • isPendingstatus === 'pending' - 查询还没有数据
  • isErrorstatus === 'error' - 查询遇到错误
  • isSuccessstatus === 'success' - 查询成功,并且数据可用

除了这些主要状态之外,根据查询的状态,还可以获得更多信息

  • error - 如果查询处于 isError 状态,则可以通过 error 属性访问错误。
  • data - 如果查询处于 isSuccess 状态,则可以通过 data 属性访问数据。
  • isFetching - 在任何状态下,如果查询在任何时候正在获取数据(包括后台重新获取),isFetching 将为 true

对于大多数查询,通常只需检查 isPending 状态,然后是 isError 状态,最后,假设数据可用并渲染成功状态

angular-ts
@Component({
  selector: 'todos',
  standalone: true,
  template: `
    @if (todos.isPending()) {
      <span>Loading...</span>
    } @else if (todos.isError()) {
      <span>Error: {{ todos.error()?.message }}</span>
    } @else {
      <!-- We can assume by this point that status === 'success' -->
      @for (todo of todos.data(); track todo.id) {
        <li>{{ todo.title }}</li>
      } @empty {
        <li>No todos found</li>
      }
    }
  `,
})
export class PostsComponent {
  todos = injectQuery(() => ({
    queryKey: ['todos'],
    queryFn: fetchTodoList,
  }))
}
@Component({
  selector: 'todos',
  standalone: true,
  template: `
    @if (todos.isPending()) {
      <span>Loading...</span>
    } @else if (todos.isError()) {
      <span>Error: {{ todos.error()?.message }}</span>
    } @else {
      <!-- We can assume by this point that status === 'success' -->
      @for (todo of todos.data(); track todo.id) {
        <li>{{ todo.title }}</li>
      } @empty {
        <li>No todos found</li>
      }
    }
  `,
})
export class PostsComponent {
  todos = injectQuery(() => ({
    queryKey: ['todos'],
    queryFn: fetchTodoList,
  }))
}

如果布尔值不是你喜欢的,你也可以使用 status 状态

angular-ts
@Component({
  selector: 'todos',
  standalone: true,
  template: `
    @switch (todos.status()) {
      @case ('pending') {
        <span>Loading...</span>
      }
      @case ('error') {
        <span>Error: {{ todos.error()?.message }}</span>
      }
      <!-- also status === 'success', but "else" logic works, too -->
      @default {
        <ul>
          @for (todo of todos.data(); track todo.id) {
            <li>{{ todo.title }}</li>
          } @empty {
            <li>No todos found</li>
          }
        </ul>
      }
    }
  `,
})
class TodosComponent {}
@Component({
  selector: 'todos',
  standalone: true,
  template: `
    @switch (todos.status()) {
      @case ('pending') {
        <span>Loading...</span>
      }
      @case ('error') {
        <span>Error: {{ todos.error()?.message }}</span>
      }
      <!-- also status === 'success', but "else" logic works, too -->
      @default {
        <ul>
          @for (todo of todos.data(); track todo.id) {
            <li>{{ todo.title }}</li>
          } @empty {
            <li>No todos found</li>
          }
        </ul>
      }
    }
  `,
})
class TodosComponent {}

如果你在访问 data 之前检查了 pendingerror,TypeScript 也会正确地缩小 data 的类型。

FetchStatus

除了 status 字段之外,你还将获得一个额外的 fetchStatus 属性,它具有以下选项

  • fetchStatus === 'fetching' - 查询当前正在获取数据。
  • fetchStatus === 'paused' - 查询想要获取数据,但它被暂停了。在 网络模式 指南中阅读更多关于此内容的信息。
  • fetchStatus === 'idle' - 查询目前没有做任何事情。

为什么是两种不同的状态?

后台重新获取和 stale-while-revalidate 逻辑使 statusfetchStatus 的所有组合都成为可能。例如

  • 处于 success 状态的查询通常会处于 idle fetchStatus,但如果正在进行后台重新获取,它也可能处于 fetching 状态。
  • 一个挂载且没有数据的查询通常会处于 pending 状态和 fetching fetchStatus,但如果没有网络连接,它也可能处于 paused 状态。

因此请记住,查询可能处于 pending 状态,但实际上并没有获取数据。作为经验法则

  • status 提供关于 data 的信息:我们有数据吗?
  • fetchStatus 提供关于 queryFn 的信息:它正在运行吗?