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

Apollo分页查询缓存已存在仍请求服务器问题排查

解决Apollo Client分页回退重复请求服务端的问题

问题根源分析

你遇到的重复请求问题,主要来自三个方面:

  • 查询变量不完整,缓存键未包含filter、debouncedSearch等影响结果的参数,导致缓存逻辑混乱
  • 总数字段privateCloudProjectsCount未配置缓存策略,每次查询都会触发服务端请求
  • 分页逻辑未判断目标页面数据是否已缓存,可能误触发fetchMore

具体解决方案

1. 补全查询变量

将filter和debouncedSearch加入useQuery和fetchMore的变量中,确保Apollo Client能根据完整参数生成唯一缓存键:

export default function Projects() {
  const { debouncedSearch } = useContext(SearchContext);
  const { filter } = useContext(FilterContext);
  const [currentPage, setCurrentPage] = useState(0);
  const pageSize = 10;

  const { loading, data, fetchMore, error } = useQuery(ALL_PROJECTS, {
    fetchPolicy: "cache-first",
    nextFetchPolicy: "cache-first",
    variables: {
      offset: 0,
      limit: pageSize,
      filter: filter,
      search: debouncedSearch,
    },
  });

  const getNextPage = useCallback(
    (page) => {
      setCurrentPage(page);
      const targetOffset = page * pageSize;
      // 仅当目标页面数据未加载时,才调用fetchMore
      const existingDataLength = data?.privateCloudProjectsPaginated?.length || 0;
      if (targetOffset >= existingDataLength) {
        fetchMore({
          variables: {
            offset: targetOffset,
            limit: pageSize,
            filter: filter,
            search: debouncedSearch,
          },
        });
      }
    },
    [filter, debouncedSearch, fetchMore, data, pageSize]
  );

  // ... 其余代码不变
}

2. 配置总数字段的缓存策略

修改InMemoryCache的typePolicies,给privateCloudProjectsCount添加缓存规则,基于filter和search缓存总条数:

const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        privateCloudProjectsPaginated: offsetLimitPagination({
          // 指定除offset/limit外的缓存键参数
          keyArgs: ['filter', 'search'],
        }),
        privateCloudProjectsCount: {
          // 总条数仅依赖filter和search,与分页参数无关
          keyArgs: ['filter', 'search'],
          merge(existing, incoming) {
            // 直接覆盖旧值,确保总条数始终最新
            return incoming;
          },
        },
      },
    },
  },
});

3. 优化表格数据切片逻辑

确保表格仅从缓存的全量数据中切片当前页内容,避免触发不必要的查询:

// 在组件中计算当前页的rows
const currentRows = useMemo(() => {
  if (!data?.privateCloudProjectsPaginated) return [];
  const start = currentPage * pageSize;
  const end = start + pageSize;
  return data.privateCloudProjectsPaginated.slice(start, end).map(projectsToRows);
}, [data, currentPage, pageSize]);

// 渲染表格时使用currentRows
return (
  <StickyTable
    onClickPath="/private-cloud/admin/project/"
    onNextPage={getNextPage}
    columns={columns}
    rows={loading ? [] : currentRows}
    count={loading ? 0 : data.privateCloudProjectsCount}
    title="Projects"
    loading={loading}
  />
);

验证效果

完成以上修改后:

  • 首次请求第一页时,从服务端获取数据并缓存
  • 切换到未加载过的页面时,调用fetchMore获取新数据并合并到缓存
  • 回退到已加载过的页面时,直接从缓存切片显示数据,不会发起服务端请求

内容的提问来源于stack exchange,提问作者Oamar Kanji

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 11:50:46