概述
重要提示:本库目前处于实验阶段。这意味着破坏性变更可能出现在次要版本(minor)和补丁版本(patch)中。请谨慎升级。若你在实验阶段将本库用于生产环境,请将版本锁定到补丁级版本,以避免意外的破坏性变更。
@tanstack/angular-query-experimental 包为通过 Angular 使用 TanStack Query 提供了一流的 API。
欢迎反馈!
我们正致力于为 Angular 上的 TanStack Query 确立稳定 API。如果你有任何反馈,请通过 TanStack Discord 服务器联系我们,或在 GitHub 上 参与此讨论。
支持的 Angular 版本
TanStack Query 兼容 Angular v16 及更高版本。
TanStack Query(原名 React Query)常被描述为 Web 应用所缺失的数据拉取库;但从技术角度看,它让 Web 应用中的 拉取、缓存、同步与更新服务端状态 变得轻而易举。
设计动机
大多数核心 Web 框架 并未提供 一种统一、有明确主张的数据拉取或更新方式。因此,开发者往往要么构建封装了严格数据拉取主张的元框架,要么自行发明数据拉取方式。这通常意味着将基于组件的状态与副作用拼凑在一起,或使用更通用的状态管理库在整个应用中存储并提供异步数据。
尽管大多数传统状态管理库在处理客户端状态(client state)方面表现出色,但它们在处理异步状态或服务端状态(server state)时却 表现欠佳。这是因为 服务端状态截然不同。首先,服务端状态:
- 远程持久化于你可能无法控制或拥有的位置
- 需要通过异步 API 进行拉取与更新
- 暗示共享所有权,且可能在你不知情的情况下被他人修改
- 若不加注意,可能在你的应用中变得“过期”
一旦你理解了应用中服务端状态的本质,后续还会涌现出更多挑战,例如:
- 缓存……(可能是编程中最难的事之一)
- 将针对同一数据的多个请求去重为单个请求
- 在后台更新“过期”的数据
- 判定数据何时“过期”
- 尽快反映数据更新
- 分页与懒加载等性能优化
- 服务端状态的内存管理与垃圾回收(garbage collection)
- 使用结构共享对查询结果进行记忆化(memoizing)
如果你未被上述列表压垮,那说明你很可能已解决所有服务端状态问题,理应获得嘉奖。然而,如果你和绝大多数开发者一样,尚未应对或仅部分应对这些挑战,那么我们才刚刚触及表层!
TanStack Query 毫无疑问是管理服务端状态的 最佳 库之一。它开箱即用、零配置,且可随应用增长按需定制。
TanStack Query 能助你攻克服务端状态带来的棘手挑战与障碍,并在服务端状态开始主导你的应用之前,先一步掌控应用数据。
从更技术的角度看,TanStack Query 很可能:
- 帮你从应用中移除 大量 复杂且易被误解的代码,仅用寥寥数行 Angular Query 逻辑即可替代
- 让应用更易维护,并在开发新功能时无需担忧新服务端状态数据源的接入
- 直接提升终端用户体验,使应用响应更快、感觉更流畅
- 潜在地节省带宽并提升内存性能
少说多做,快让我看看代码!
以下示例展示了 TanStack Query 最基础、最简单的用法:拉取 TanStack Query 自身 GitHub 项目的 GitHub 统计信息:
1import { ChangeDetectionStrategy, Component, inject } from '@angular/core'2import { HttpClient } from '@angular/common/http'3import { injectQuery } from '@tanstack/angular-query-experimental'4import { lastValueFrom } from 'rxjs'5 6@Component({7 changeDetection: ChangeDetectionStrategy.OnPush,8 selector: 'simple-example',9 template: `10 @if (repoDataQuery.isPending()) {11 Loading...12 }13 @if (repoDataQuery.isError()) {14 An error has occurred: {{ repoDataQuery.error().message }}15 }16 @if (repoDataQuery.data(); as data) {17 <h1>{{ data.name }}</h1>18 <p>{{ data.description }}</p>19 <strong>👀 {{ data.subscribers_count }}</strong>20 <strong>✨ {{ data.stargazers_count }}</strong>21 <strong>🍴 {{ data.forks_count }}</strong>22 }23 `,24})25export class SimpleExampleComponent {26 readonly http = inject(HttpClient)27 28 readonly repoDataQuery = injectQuery(() => ({29 queryKey: ['repoData'],30 queryFn: () =>31 lastValueFrom(32 this.http.get<Repo>('https://api.github.com/repos/TanStack/query'),33 ),34 }))35}36 37interface Repo {38 name: string39 description: string40 subscribers_count: number41 stargazers_count: number42 forks_count: number43}