Apollo Client Relay风格分页:求分页读取函数示例
自定义relayStylePagination分页读取函数示例
默认relayStylePagination生成的read函数会忽略查询参数,直接返回缓存中所有合并后的分页数据。如果需要让它根据传入的分页参数(如first、after)返回单页数据,可以按以下方式自定义:
1. 覆盖read函数的自定义字段策略
import { relayStylePagination } from '@apollo/client/utilities'; import { gql, InMemoryCache } from '@apollo/client'; // 基于默认relay策略扩展 const customRelayPagination = relayStylePagination(); // 重写read方法 customRelayPagination.read = function (existing, { args, cache }) { // 先调用默认read获取所有缓存的分页数据 const fullDataset = relayStylePagination().read(existing, { args, cache }); // 无分页参数时返回全部数据,兼容原有逻辑 if (!args?.first) return fullDataset; let startIdx = 0; // 处理after游标,定位起始位置 if (args.after) { // 读取游标对应的节点(需根据你的游标格式调整缓存ID和Fragment) const targetNode = cache.readFragment({ id: `YourNodeType:${args.after}`, // 示例:假设游标是节点ID,缓存ID格式为"类型:ID" fragment: gql` fragment NodeIdFragment on YourNodeType { id } `, }); if (targetNode) { // 找到该节点在edges中的位置,下一个位置就是分页起始点 startIdx = fullDataset.edges.findIndex(edge => edge.node.id === targetNode.id) + 1; } } // 截取对应数量的条目 const paginatedEdges = fullDataset.edges.slice(startIdx, startIdx + args.first); // 返回符合分页要求的结构,更新pageInfo状态 return { ...fullDataset, edges: paginatedEdges, pageInfo: { ...fullDataset.pageInfo, hasNextPage: paginatedEdges.length === args.first, hasPreviousPage: startIdx > 0, }, }; }; // 在缓存配置中使用自定义策略 const cache = new InMemoryCache({ typePolicies: { Query: { fields: { // 替换成你的分页字段名,比如"posts"、"comments" yourPaginatedField: customRelayPagination, }, }, }, });
2. fetchMore后更新查询变量
自定义read函数依赖查询参数返回对应页面,因此调用fetchMore后必须更新原始查询的变量,确保组件重新渲染时read函数能拿到正确参数:
import { useQuery } from '@apollo/client'; const YOUR_PAGINATED_QUERY = gql` query GetItems($first: Int!, $after: String) { yourPaginatedField(first: $first, after: $after) { edges { node { id /* 其他字段 */ } } pageInfo { endCursor hasNextPage } } } `; function YourComponent() { const { data, fetchMore, variables, setVariables } = useQuery(YOUR_PAGINATED_QUERY, { variables: { first: 10, after: null }, }); const handleLoadNextPage = async () => { if (!data?.yourPaginatedField?.pageInfo?.hasNextPage) return; await fetchMore({ variables: { after: data.yourPaginatedField.pageInfo.endCursor, }, }); // 更新原始查询变量,让read函数下次用新参数返回对应页 setVariables({ ...variables, after: data.yourPaginatedField.pageInfo.endCursor, }); }; return ( // 组件渲染逻辑 ); }
关键注意点
- 游标的缓存ID格式需要和你的实际情况匹配:如果后端返回的游标不是节点ID,需要调整
cache.readFragment中的id参数,比如有些后端会返回编码后的游标,这时可能需要先解码再匹配节点。 pageInfo的hasNextPage和hasPreviousPage需要根据截取后的结果重新计算,保证前端分页控件状态正确。
内容的提问来源于stack exchange,提问作者Treznorx
相关产品推荐
相关产品推荐

