React中如何结合AG Grid(服务端行模型)与Apollo GraphQL实现Relay式游标分页?
使用Apollo Client(Relay风格游标分页)对接AG Grid服务端行模型
核心思路
AG Grid的服务端行模型(Server-Side Row Model)允许完全自定义数据加载逻辑,刚好适配Relay Connection模式的游标分页。核心是实现自定义ServerSideDatasource,在其中根据滚动状态构造带after游标的GraphQL查询,同时利用Apollo的relayStylePagination完成缓存数据的自动合并。
1. 配置AG Grid基础参数
先开启服务端行模型和无限滚动能力:
<AgGridReact rowModelType="serverSide" pagination={false} enableInfiniteScroll={true} rowBuffer={20} // 提前加载20行,避免滚动时出现空白 onGridReady={handleGridReady} // 你的列配置等其他参数 />
2. 实现自定义数据源
在组件中维护分页状态(最后一个游标、是否还有更多数据),然后实现ServerSideDatasource的getRows方法——这是数据加载的核心逻辑:
import { useApolloClient } from '@apollo/client'; import { useState } from 'react'; import { AgGridReact } from 'ag-grid-react'; const YourGridComponent = () => { const client = useApolloClient(); const [lastCursor, setLastCursor] = useState(null); const [hasMore, setHasMore] = useState(true); const [isLoading, setIsLoading] = useState(false); const handleGridReady = (params) => { const datasource = { getRows: async (gridParams) => { // 防止重复请求或无更多数据时直接返回 if (isLoading || !hasMore) { gridParams.success({ rowData: [], rowCount: -1 }); return; } setIsLoading(true); try { // 发起带游标参数的GraphQL查询 const { data } = await client.query({ query: YOUR_CONNECTION_QUERY, // 替换为你的Connection模式查询 variables: { first: 10, // 每页加载条数,可按需调整 after: lastCursor, // 首次请求为null,后续用上次返回的endCursor }, }); const { edges, pageInfo } = data.yourConnection; const rowData = edges.map(edge => edge.node); // 更新分页状态 setLastCursor(pageInfo.endCursor); setHasMore(pageInfo.hasNextPage); // 通知AG Grid数据加载完成 gridParams.success({ rowData, rowCount: -1, // 不确定总条数时传-1,AG Grid会自动触发后续请求 }); } catch (err) { gridParams.fail(); console.error('数据加载失败:', err); } finally { setIsLoading(false); } }, }; params.api.setServerSideDatasource(datasource); }; return <AgGridReact {/* 配置参数 */} />; };
3. 配置Apollo缓存合并
确保Apollo的InMemoryCache配置relayStylePagination,让它自动合并多次分页请求的缓存数据:
import { InMemoryCache, relayStylePagination } from '@apollo/client'; const cache = new InMemoryCache({ typePolicies: { Query: { fields: { yourConnection: relayStylePagination(), // 替换为你的Connection字段名 }, }, }, }); // 将此cache传入ApolloClient实例
4. 处理排序/过滤(可选)
如果需要支持排序或过滤,要在getRows中提取AG Grid的请求参数,重置分页状态并更新查询变量:
// 在组件中新增状态跟踪排序/过滤条件 const [currentSort, setCurrentSort] = useState([]); const [currentFilter, setCurrentFilter] = useState({}); // 在getRows方法中加入以下逻辑: const { sortModel, filterModel } = gridParams.request; // 排序/过滤条件变化时,重置分页状态 const sortChanged = JSON.stringify(sortModel) !== JSON.stringify(currentSort); const filterChanged = JSON.stringify(filterModel) !== JSON.stringify(currentFilter); if (sortChanged || filterChanged) { setLastCursor(null); setHasMore(true); setCurrentSort(sortModel); setCurrentFilter(filterModel); } // 构造查询变量时加入排序/过滤参数 const variables = { first: 10, after: lastCursor, sort: sortModel.map(item => ({ field: item.colId, direction: item.sort })), filter: filterModel, };
关键注意点
- 确保你的GraphQL API返回标准Relay Connection字段:
edges(包含node和cursor)、pageInfo(包含endCursor和hasNextPage)。 - AG Grid的
rowCount设为-1时,会持续请求数据直到hasMore为false;如果知道总条数,也可以传入具体数值。 - 加入
isLoading状态可以避免滚动时重复触发请求,提升用户体验。
内容的提问来源于stack exchange,提问作者Erland Glad Solstrand
相关产品推荐
相关产品推荐

