angular-query
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese@tanstack/angular-query-experimental
@tanstack/angular-query-experimental
Version: 5.x (2025)
Tags: Data Fetching, Server State, Caching, TanStack Query
API Changes
API 变更
This section documents version-specific API changes.
-
NEW: Angular Query v5 — Signal-based API for TanStack Query source
-
NEW:— Signal-based query injection
injectQuery -
NEW:— Signal-based mutation injection
injectMutation -
NEW: Query options pattern — Service-based query configuration
-
NEW: DevTools integration — Angular Query DevTools for debugging
本部分记录对应版本的 API 变动内容。
-
新增:Angular Query v5 — 基于 Signal 的 TanStack Query API 来源
-
新增:— 基于 Signal 的查询注入能力
injectQuery -
新增:— 基于 Signal 的变更操作注入能力
injectMutation -
新增:查询选项模式 — 基于服务的查询配置方案
-
新增:DevTools 集成 — 用于调试的 Angular Query 开发者工具
Best Practices
最佳实践
- Install and setup
bash
npm install @tanstack/angular-query-experimentalts
import { provideHttpClient } from '@angular/common/http';
import { provideTanStackQuery } from '@tanstack/angular-query-experimental';
import { QueryClient } from '@tanstack/query-core';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(),
provideTanStackQuery(new QueryClient())
]
};- Use injectQuery for data fetching
ts
import { injectQuery } from '@tanstack/angular-query-experimental';
@Component({})
export class TodosComponent {
private http = inject(HttpClient);
query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => lastValueFrom(this.http.get<Todo[]>('/api/todos'))
}));
}- Use in templates with signals
ts
@Component({
template: `
@if (query.isPending()) {
Loading...
} @else if (query.isError()) {
Error: {{ query.error().message }}
} @else {
@for (todo of query.data(); track todo.id) {
{{ todo.title }}
}
}
`
})
export class TodosComponent {
query = injectQuery(() => ({ ... }));
}- Use mutations for data modification
ts
import { injectMutation, injectQueryClient } from '@tanstack/angular-query-experimental';
@Component({})
export class AddTodoComponent {
private http = inject(HttpClient);
private queryClient = injectQueryClient();
mutation = injectMutation(() => ({
mutationFn: (newTodo: string) =>
lastValueFrom(this.http.post('/api/todos', { title: newTodo })),
onSuccess: () => {
this.queryClient.invalidateQueries({ queryKey: ['todos'] });
}
}));
addTodo(title: string) {
this.mutation.mutate(title);
}
}- Use query options for reusable queries
ts
@Injectable({ providedIn: 'root' })
export class TodoService {
private http = inject(HttpClient);
getTodoOptions = (id: number) => queryOptions({
queryKey: ['todo', id],
queryFn: () => lastValueFrom(this.http.get(`/api/todos/${id}`))
});
}
@Component({})
export class TodoComponent {
private todoService = inject(TodoService);
todo = this.todoService.getTodoOptions(1);
}- Handle loading and error states
ts
query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => fetchTodos(),
retry: 3,
staleTime: 1000 * 60 * 5, // 5 minutes
refetchOnWindowFocus: false
}));- Use invalidation for cache updates
ts
mutation = injectMutation(() => ({
mutationFn: createTodo,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] });
}
}));- Use optimistic updates
ts
mutation = injectMutation(() => ({
mutationFn: updateTodo,
onMutate: async (newTodo) => {
await queryClient.cancelQueries({ queryKey: ['todos'] });
const previousTodos = queryClient.getQueryData(['todos']);
queryClient.setQueryData(['todos'], (old: Todo[]) => [...old, newTodo]);
return { previousTodos };
},
onError: (err, newTodo, context) => {
queryClient.setQueryData(['todos'], context.previousTodos);
}
}));- 安装与初始化配置
bash
npm install @tanstack/angular-query-experimentalts
import { provideHttpClient } from '@angular/common/http';
import { provideTanStackQuery } from '@tanstack/angular-query-experimental';
import { QueryClient } from '@tanstack/query-core';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(),
provideTanStackQuery(new QueryClient())
]
};- 使用 injectQuery 实现数据获取
ts
import { injectQuery } from '@tanstack/angular-query-experimental';
@Component({})
export class TodosComponent {
private http = inject(HttpClient);
query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => lastValueFrom(this.http.get<Todo[]>('/api/todos'))
}));
}- 配合 signals 在模板中使用
ts
@Component({
template: `
@if (query.isPending()) {
加载中...
} @else if (query.isError()) {
错误:{{ query.error().message }}
} @else {
@for (todo of query.data(); track todo.id) {
{{ todo.title }}
}
}
`
})
export class TodosComponent {
query = injectQuery(() => ({ ... }));
}- 使用 mutations 实现数据修改
ts
import { injectMutation, injectQueryClient } from '@tanstack/angular-query-experimental';
@Component({})
export class AddTodoComponent {
private http = inject(HttpClient);
private queryClient = injectQueryClient();
mutation = injectMutation(() => ({
mutationFn: (newTodo: string) =>
lastValueFrom(this.http.post('/api/todos', { title: newTodo })),
onSuccess: () => {
this.queryClient.invalidateQueries({ queryKey: ['todos'] });
}
}));
addTodo(title: string) {
this.mutation.mutate(title);
}
}- 使用查询选项实现可复用查询
ts
@Injectable({ providedIn: 'root' })
export class TodoService {
private http = inject(HttpClient);
getTodoOptions = (id: number) => queryOptions({
queryKey: ['todo', id],
queryFn: () => lastValueFrom(this.http.get(`/api/todos/${id}`))
});
}
@Component({})
export class TodoComponent {
private todoService = inject(TodoService);
todo = this.todoService.getTodoOptions(1);
}- 处理加载与错误状态
ts
query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => fetchTodos(),
retry: 3,
staleTime: 1000 * 60 * 5, // 5分钟
refetchOnWindowFocus: false
}));- 使用失效机制更新缓存
ts
mutation = injectMutation(() => ({
mutationFn: createTodo,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] });
}
}));- 使用乐观更新
ts
mutation = injectMutation(() => ({
mutationFn: updateTodo,
onMutate: async (newTodo) => {
await queryClient.cancelQueries({ queryKey: ['todos'] });
const previousTodos = queryClient.getQueryData(['todos']);
queryClient.setQueryData(['todos'], (old: Todo[]) => [...old, newTodo]);
return { previousTodos };
},
onError: (err, newTodo, context) => {
queryClient.setQueryData(['todos'], context.previousTodos);
}
}));