Angular 7中Apollo GraphQL查询仅执行一次,如何重新触发?
解决Apollo GraphQL查询在Angular中无法按需触发的问题
我看了你的代码,发现问题主要出在两个地方:查询参数没有正确更新,以及没有利用Apollo Client提供的查询刷新机制。下面给你分步解决:
1. 先修复分页参数的错误
你在onPageChanged里没有更新skip的值!当前页码变化时,skip应该是pageIndex * pageSize,而不是保持初始的0。这就是为什么你触发分页后查询结果没变化的核心原因之一。
2. 用Apollo Client的refetch方法优雅刷新查询
Apollo的watch方法返回的ApolloQueryObservable自带refetch方法,可以直接触发重新查询,不需要重新创建Observable并赋值给authors$。这样既高效,又能让模板里的async管道自动接收新数据。
修改后的代码如下:
import { Component, OnInit } from '@angular/core'; import { AdminAuthorsGQL, Authors } from 'src/generated-models'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { PageEvent } from '@angular/material'; // 别忘了导入ApolloQueryObservable import { ApolloQueryObservable } from 'apollo-angular'; @Component({ selector: "app-admin-authors", templateUrl: "./admin-authors.component.html", styleUrls: ["./admin-authors.component.scss"] }) export class AdminAuthorsComponent implements OnInit { public displayedColumns: string[] = ['no', 'image', 'name', 'translator', 'books', 'transactions']; public table = { display: false, text: 'table' }; public form = { display: false, text: 'form' }; authors$: Observable<Authors.Authors[]>; // 新增:保存watch返回的查询对象 private authorsQuery: ApolloQueryObservable<any>; pageEvent: PageEvent; pageSize: number = 25; // default skip: number = 0; length = 1000; pageSizeOptions: number[] = [5, 10, 25, 50, 100]; isLoadingResults: boolean = false; isNoDataFound: boolean = false; constructor(private adminAuthorsGql: AdminAuthorsGQL) {} ngOnInit() { // 先创建查询对象并保存 this.authorsQuery = this.adminAuthorsGql.watch({ skip: this.skip, limit: this.pageSize }); // 从查询对象中获取数据Observable this.authors$ = this.authorsQuery.valueChanges.pipe( map(result => { // 这里可以顺便更新总条数(如果你的接口返回total的话) this.length = result.data.authorsWithPaginate.total; return result.data.authorsWithPaginate.items; // 假设你的结构是items+total,根据实际调整 }) ); this.isLoadingResults = false; this.isNoDataFound = false; } setPageSizeOptions(setPageSizeOptionsInput: string) { this.pageSizeOptions = setPageSizeOptionsInput.split(',').map(str => +str); } onPageChanged(e: PageEvent) { console.log(e); // 正确计算skip值 this.skip = e.pageIndex * e.pageSize; this.pageSize = e.pageSize; // 用refetch触发重新查询,传入新参数 this.authorsQuery.refetch({ skip: this.skip, limit: this.pageSize }); // 如果需要加载状态,可以在这里设置isLoadingResults为true,然后在valueChanges里设为false } // 其他方法保持不变... authorEdit(id) { this.table.display = !this.table.display; console.log('authorEdit:',id, this.table.display); } authorDelete(id) { this.table.display = !this.table.display; console.log('authorDelete:',id, this.table.display); } onRowClicked(row) { console.log('Row clicked: ', row); } }
3. 更响应式的方案:用BehaviorSubject管理查询参数
如果希望参数变化时自动触发查询(比如不仅分页,还有搜索、筛选等场景),可以用BehaviorSubject来管理查询参数,通过switchMap自动订阅新的查询:
import { Component, OnInit } from '@angular/core'; import { AdminAuthorsGQL, Authors } from 'src/generated-models'; import { Observable, BehaviorSubject } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; import { PageEvent } from '@angular/material'; @Component({ selector: "app-admin-authors", templateUrl: "./admin-authors.component.html", styleUrls: ["./admin-authors.component.scss"] }) export class AdminAuthorsComponent implements OnInit { // ...其他属性不变 // 新增:用BehaviorSubject存储查询参数,初始值为默认分页参数 private queryParams$ = new BehaviorSubject({ skip: 0, limit: 25 }); constructor(private adminAuthorsGql: AdminAuthorsGQL) {} ngOnInit() { // 监听参数变化,自动触发查询 this.authors$ = this.queryParams$.pipe( switchMap(params => this.adminAuthorsGql.watch(params).valueChanges.pipe( map(result => { this.length = result.data.authorsWithPaginate.total; return result.data.authorsWithPaginate.items; }) ) ) ); } onPageChanged(e: PageEvent) { this.skip = e.pageIndex * e.pageSize; this.pageSize = e.pageSize; // 只需要更新参数Subject,自动触发查询 this.queryParams$.next({ skip: this.skip, limit: this.pageSize }); } // ...其他方法不变 }
为什么你的原代码不生效?
- 首先,
skip值没有更新,导致每次查询的都是第一页数据,看起来没变化; - 其次,即使你正确更新了
skip,重新赋值authors$虽然能让async管道重新订阅,但这不是最优解——Apollo已经帮你维护了查询的订阅状态,用refetch或参数Subject的方式更高效、更符合RxJS和Apollo的设计理念。
内容的提问来源于stack exchange,提问作者umutyerebakmaz
相关产品推荐
相关产品推荐

