You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 03:59:15