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

Apollo Client页面刷新后Pending请求计数失效的修复咨询

解决方案:修复页面刷新后Pending请求计数失效问题

问题根源

你当前的实现存在三个核心问题:

  1. 动态修改Apollo Client链接时机错误:在组件内部通过client.setLink添加middlewareLink,页面刷新后部分请求(比如应用初始化时的请求)可能在组件挂载前就已发送,不会经过新创建的middlewareLink,导致计数不更新。
  2. 未处理完整请求生命周期:只在请求完成时减少计数,未处理请求错误、订阅取消(比如组件卸载导致请求中止)的场景,会导致计数不准确。
  3. 轮询方式低效:用setInterval轮询获取计数不是响应式的最佳实践,容易出现状态不同步。

方案1:基于RxJS的响应式实现(推荐)

利用RxJS的BehaviorSubject实现计数的响应式更新,确保所有请求都经过middlewareLink:

1. 重构Pending请求链接

import { ApolloLink } from '@apollo/client';
import { BehaviorSubject } from 'rxjs';

export const createPendingRequestsLink = () => {
  const pendingRequests$ = new BehaviorSubject(0);
  let pendingRequests = 0;

  const middlewareLink = new ApolloLink((operation, forward) => {
    // 请求开始时增加计数
    pendingRequests++;
    pendingRequests$.next(pendingRequests);

    return new Observable((observer) => {
      const subscription = forward(operation).subscribe({
        next: (result) => observer.next(result),
        error: (error) => {
          observer.error(error);
          // 请求出错时减少计数
          pendingRequests--;
          pendingRequests$.next(pendingRequests);
        },
        complete: () => {
          observer.complete();
          // 请求完成时减少计数
          pendingRequests--;
          pendingRequests$.next(pendingRequests);
        },
      });

      return () => {
        // 请求被取消时减少计数
        pendingRequests--;
        pendingRequests$.next(pendingRequests);
        subscription?.unsubscribe();
      };
    });
  });

  return { middlewareLink, pendingRequests$ };
};

2. 初始化Apollo Client时注入链接

在全局的Apollo Client初始化文件中(比如apolloClient.js),把middlewareLink加入链接链:

import { ApolloClient, InMemoryCache, ApolloLink, HttpLink } from '@apollo/client';
import { createPendingRequestsLink } from './path-to-your-link-file';

const { middlewareLink, pendingRequests$ } = createPendingRequestsLink();
const httpLink = new HttpLink({ uri: '/your-graphql-endpoint' });

const client = new ApolloClient({
  link: ApolloLink.from([middlewareLink, httpLink]),
  cache: new InMemoryCache(),
});

// 导出供组件使用
export { client, pendingRequests$ };

3. 组件中订阅计数变化

import { useState, useEffect } from 'react';
import { pendingRequests$ } from './apolloClient';

function YourComponent() {
  const [pendingCount, setPendingCount] = useState(0);

  useEffect(() => {
    // 订阅计数变化,自动更新组件状态
    const subscription = pendingRequests$.subscribe(count => setPendingCount(count));
    return () => subscription.unsubscribe();
  }, []);

  return (
    <div>
      {/* 根据计数显示加载动画 */}
      {pendingCount > 0 && <div className="spinner">加载中...</div>}
      {/* 你的组件内容 */}
    </div>
  );
}

方案2:纯React Context实现(无需RxJS)

如果不想引入RxJS,可以用React Context管理计数状态:

1. 创建Pending请求Context

import { createContext, useContext, useState } from 'react';

const PendingRequestsContext = createContext();

export function PendingRequestsProvider({ children }) {
  const [pendingCount, setPendingCount] = useState(0);
  return (
    <PendingRequestsContext.Provider value={{ pendingCount, setPendingCount }}>
      {children}
    </PendingRequestsContext.Provider>
  );
}

export function usePendingRequests() {
  return useContext(PendingRequestsContext);
}

2. 重构Pending请求链接

import { ApolloLink } from '@apollo/client';

export const createPendingRequestsLink = (setPendingCount) => {
  let pendingRequests = 0;

  return new ApolloLink((operation, forward) => {
    pendingRequests++;
    setPendingCount(pendingRequests);

    return new Observable((observer) => {
      const subscription = forward(operation).subscribe({
        next: (result) => observer.next(result),
        error: (error) => {
          observer.error(error);
          pendingRequests--;
          setPendingCount(pendingRequests);
        },
        complete: () => {
          observer.complete();
          pendingRequests--;
          setPendingCount(pendingRequests);
        },
      });

      return () => {
        pendingRequests--;
        setPendingCount(pendingRequests);
        subscription?.unsubscribe();
      };
    });
  });
};

3. 全局注入Client和Context

import { ApolloProvider, ApolloClient, InMemoryCache, ApolloLink, HttpLink } from '@apollo/client';
import { PendingRequestsProvider, usePendingRequests } from './path-to-context';
import { createPendingRequestsLink } from './path-to-link';

function ApolloWrapper({ children }) {
  const { setPendingCount } = usePendingRequests();
  const httpLink = new HttpLink({ uri: '/your-graphql-endpoint' });
  const middlewareLink = createPendingRequestsLink(setPendingCount);

  const client = new ApolloClient({
    link: ApolloLink.from([middlewareLink, httpLink]),
    cache: new InMemoryCache(),
  });

  return <ApolloProvider client={client}>{children}</ApolloProvider>;
}

function App() {
  return (
    <PendingRequestsProvider>
      <ApolloWrapper>
        {/* 你的应用组件 */}
      </ApolloWrapper>
    </PendingRequestsProvider>
  );
}

4. 组件中使用计数

import { usePendingRequests } from './path-to-context';

function YourComponent() {
  const { pendingCount } = usePendingRequests();

  return (
    <div>
      {pendingCount > 0 && <div className="spinner">加载中...</div>}
      {/* 你的组件内容 */}
    </div>
  );
}

旧问题补充说明

针对你最初的需求(监控所有Pending请求),上面的方案已经完全覆盖:通过Apollo Link拦截所有请求的生命周期,统一维护Pending请求计数,无需再单独监控单个watchQuery的networkStatus。

内容的提问来源于stack exchange,提问作者Alberto Manuguerra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 20:35:05