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

如何用Apollo Client实现多列表GraphQL fetchMore分页,避免重复请求

多列表独立分页实现方案(Apollo Client + Server)

针对你页面中三个横向滚动列表的分页需求,以下是具体实现步骤,满足初始一次请求、单列表分页不影响其他列表的要求:

1. 初始数据加载

直接使用你提供的查询语句,页面初始化时传入所有offset为0的变量,一次请求拉取三个列表的第一页数据:

const { data, fetchMore, loading } = useQuery(QUERY, {
  variables: {
    favoritesOffset: 0,
    featuredOffset: 0,
    recentOffset: 0,
  },
});

Apollo Client会自动将这次请求的结果缓存起来,后续操作基于此缓存进行更新。

2. 单列表下一页加载逻辑

当用户滚动到某个列表底部时,只更新对应列表的offset参数,通过fetchMore方法拉取下一页数据,并合并到现有缓存中,不修改其他列表的数据。

以加载「favorites」列表下一页为例:

const loadMoreFavorites = () => {
  // 计算下一页的offset:当前已加载的条目数(因为每页limit是5)
  const currentLoadedCount = data?.favorites?.length || 0;
  const nextOffset = currentLoadedCount;

  fetchMore({
    // 仅更新favorites的offset变量,其他变量保持原有值
    variables: { favoritesOffset: nextOffset },
    // 合并新旧数据,只更新favorites字段
    updateQuery: (prevData, { fetchMoreResult }) => {
      if (!fetchMoreResult) return prevData;
      return {
        ...prevData,
        favorites: [...prevData.favorites, ...fetchMoreResult.favorites],
        // featured和recent字段直接沿用之前的缓存数据,不做修改
      };
    },
  });
};

同理,「featured」和「recent」列表的加载逻辑只需替换对应的offset变量即可:

// 加载featured下一页
const loadMoreFeatured = () => {
  const currentLoadedCount = data?.featured?.length || 0;
  fetchMore({
    variables: { featuredOffset: currentLoadedCount },
    updateQuery: (prevData, { fetchMoreResult }) => {
      if (!fetchMoreResult) return prevData;
      return {
        ...prevData,
        featured: [...prevData.featured, ...fetchMoreResult.featured],
      };
    },
  });
};

// 加载recent下一页(注意recent的limit是10,offset计算逻辑一致)
const loadMoreRecent = () => {
  const currentLoadedCount = data?.recent?.length || 0;
  fetchMore({
    variables: { recentOffset: currentLoadedCount },
    updateQuery: (prevData, { fetchMoreResult }) => {
      if (!fetchMoreResult) return prevData;
      return {
        ...prevData,
        recent: [...prevData.recent, ...fetchMoreResult.recent],
      };
    },
  });
};

3. 服务端适配建议

为了让前端能判断是否还有更多数据可加载,建议在listResponse片段中增加totalCount字段(需要服务端resolver支持返回总条目数):

fragment listResponse on EventList {
  items {
    id
    title
    # 你的其他业务字段
  }
  totalCount # 该类型下的总条目数
}

对应的查询语句也要调整为返回包含items和totalCount的结构:

query Sections(
  $favoritesOffset: Int = 0
  $featuredOffset: Int = 0
  $recentOffset: Int = 0
) {
  favorites: events(limit: 5, offset: $favoritesOffset, search: "FAVORITES") {
    items { ...listResponseFields }
    totalCount
  }
  # ... 其他列表同理
}

fragment listResponseFields on Event {
  id
  title
  # 业务字段
}

前端就可以通过data.favorites.totalCount > data.favorites.items.length来判断是否还有下一页,避免无效请求。

4. 缓存注意事项

  • Apollo Client会自动缓存不同参数的查询,但updateQuery会将新数据合并到初始的缓存条目里,确保组件始终能拿到该列表的全部已加载数据。
  • 如果需要更精细的缓存控制,可以使用cache.modify手动更新缓存,但fetchMore的updateQuery已经足够满足当前需求。

内容的提问来源于stack exchange,提问作者Jeremy Gillick

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 23:10:43