Apollo Client递归获取Relay风格分页全量数据的问题
解决Apollo Client自动加载全部分页数据的问题
你的代码存在两个核心问题:分页参数传递错误导致重复请求同一页面,以及networkStatus判断逻辑不完整导致无法持续触发后续请求,进而出现仅两次请求且缓存有重复对象的情况。以下是修复方案:
核心问题分析
- 参数传递错误:初始查询的分页参数嵌套在
pageArgs中,但fetchMore时直接传递了after和first,后端无法识别正确的分页条件,导致重复返回第一页数据,最终缓存出现重复条目。 - 请求触发逻辑缺陷:仅监听
networkStatus === NetworkStatus.ready,未考虑fetchMore执行时的状态变化,同时缺少请求状态锁,可能导致重复触发或中断后续请求。
修复后的代码
import { useQuery, NetworkStatus } from '@apollo/client'; import { useEffect, useState } from 'react'; const { data, loading, networkStatus, fetchMore, } = useCustomQuery({ variables: { pageArgs: { first: 1, // 可根据实际需求调整每页数量 }, }, notifyOnNetworkStatusChange: true, }); const items = data?.customQuery?.edges.map((edge) => edge.node) || []; const currentPageInfo = data?.customQuery?.pageInfo; const nextCursor = currentPageInfo?.endCursor; const hasNextPage = currentPageInfo?.hasNextPage; // 添加状态锁,避免并发请求 const [isFetchingMore, setIsFetchingMore] = useState(false); useEffect(() => { // 仅当:非初始加载、有下一页、当前未在请求更多数据、请求状态完成 if (!loading && hasNextPage && !isFetchingMore && networkStatus === NetworkStatus.ready) { setIsFetchingMore(true); fetchMore({ // 修正参数结构,与初始查询保持一致 variables: { pageArgs: { after: nextCursor, first: 1, }, }, updateQuery(previousResult: CustomQuery, { fetchMoreResult }) { if (!fetchMoreResult?.customQuery) { setIsFetchingMore(false); return previousResult; } const mergedEdges = [ ...previousResult.customQuery.edges, // 过滤重复条目,基于node的唯一id ...fetchMoreResult.customQuery.edges.filter( (newEdge) => !previousResult.customQuery.edges.some( (prevEdge) => prevEdge.node.id === newEdge.node.id ) ) ]; const updatedResult = { ...previousResult, customQuery: { ...previousResult.customQuery, edges: mergedEdges, pageInfo: fetchMoreResult.customQuery.pageInfo, }, }; setIsFetchingMore(false); return updatedResult; }, }); } }, [loading, hasNextPage, nextCursor, networkStatus, fetchMore, isFetchingMore]);
关键修改说明
- 修正参数结构:将
fetchMore的分页参数嵌套到pageArgs中,与初始查询的参数结构保持一致,确保后端能正确识别分页条件,避免重复请求同一页面。 - 添加请求状态锁:通过
isFetchingMore状态防止并发请求,避免同一时间发起多个fetchMore请求导致的逻辑混乱。 - 优化触发条件:增加
!loading和!isFetchingMore的判断,确保仅在初始加载完成且没有正在进行的请求时,才触发下一页数据获取。 - 更新状态锁时机:在
updateQuery中及时重置isFetchingMore状态,确保后续请求能正常触发。
内容的提问来源于stack exchange,提问作者coler-j
相关产品推荐
相关产品推荐

