示例说明
Relay 连接规范把分页元数据内嵌到响应里:edges 携带每条数据的游标,pageInfo 的 hasNextPage 与 endCursor 告诉调用方是否还有下一页以及从哪里继续。相比 offset 分页,游标在数据插入删除后依然稳定,不会漏页或重页。这个封装把翻页循环收敛成一个返回全量的异步函数。
技术要点
- endCursor 是下一页的起点游标
- hasNextPage 决定循环终止条件
- 变量定义让查询可被服务端缓存复用
代码解读
查询把 first 与 after 声明为 GraphQL 变量而不是拼进查询文本,同一文档可复用;fetchAllOrders 用 while 循环不断以 endCursor 作为下一轮 after 值请求,把 edges 的 node 展平累积到结果数组,hasNextPage 为假时跳出循环。
使用建议
全量拉取仅适合离线同步任务,在线列表应该单页渲染与增量加载。pageSize 过大会加大单次响应延迟与内存峰值,按下游承受力调整。请求失败时应保留已完成页,断点续传从上个游标继续。
代码示例
import { GraphQLClient, gql } from 'graphql-request';
const client = new GraphQLClient('https://api.example.com/graphql', {
headers: { Authorization: 'Bearer ' + process.env.API_TOKEN },
});
const query = gql`
query Orders($first: Int!, $after: String) {
orders(first: $first, after: $after) {
edges { cursor node { id total } }
pageInfo { hasNextPage endCursor }
}
}
`;
async function fetchAllOrders(pageSize = 50) {
const results = [];
let after = null;
while (true) {
const data = await client.request(query, { first: pageSize, after });
const { edges, pageInfo } = data.orders;
results.push(...edges.map((edge) => edge.node));
if (!pageInfo.hasNextPage) break;
after = pageInfo.endCursor;
}
return results;
}
const orders = await fetchAllOrders();
console.log('total orders fetched:', orders.length);