如何结合usePaginationFragment(带Connection)正确使用useSubscription与updater
问题:Relay分页Connection的订阅updater实现困惑
我正尝试在包含edges、且Relay Store内指定Connection的分页片段上实现订阅,使用useSubscription提供的updater变量。分页查询片段本身运行正常,且已验证Schema返回的订阅数据/数据类型与Connection中存储的匹配。Relay文档在高级分页与订阅方面的说明较为晦涩,希望能获得相关帮助!
分页查询片段
const paginatedQuery = graphql` fragment ImageViewerBuildFragment on Query @argumentDefinitions( after: { type: "String" } first: { type: "Int", defaultValue: 20 } before: { type: "String" } last: { type: "Int" } GetFilesInput: { type: "GetFilesInput!" } ) @refetchable(queryName: "ImageViewerPaginationQuery") { files(input: $GetFilesInput, after: $after, first: $first, before: $before, last: $last) @connection(key: "ImageViewer_files") { __id edges { cursor node { contentLength contentType createdBy displayName keyName keyValue fileGuid notes { note } tags { tag } thumbnailBase64 } } pageInfo { endCursor hasNextPage hasPreviousPage startCursor } totalCount } } `;
订阅相关片段
const imageSubscriptionFragment = graphql` fragment ImageViewerBuildFragment_Subscription on Subscription { monitorFiles(input: $MonitorFilesInput) { files { edges { cursor node { contentLength contentType createdBy displayName keyName keyValue fileGuid notes { note } tags { tag } thumbnailBase64 } } pageInfo { endCursor hasNextPage hasPreviousPage startCursor } totalCount } } } `; const imageSubscription = graphql` subscription ImageViewerBuildSubscription($MonitorFilesInput: MonitorFilesInput!) { ...ImageViewerBuildFragment_Subscription } `;
当前updater实现
function updater(store: RecordSourceSelectorProxy) { // console.log('store', store); // connectionID is passed as input to the mutation/subscription const connection = store.get(data.files.__id); // console.log(connection); // ... } const subscriptionConfig = useMemo( () => ({ subscription: imageSubscription, variables: { MonitorFilesInput: { keyName: 'CaseFileId', keyValue: `${caseFileId}`, }, }, updater, }), [caseFileId, imageSubscription] ); useSubscription<any>(subscriptionConfig);
补充说明
data.files.__id是原始分页查询片段返回的Connection ID。我尝试过用Connection Handler获取Connection ID但未成功,不过因能访问原始分页查询的数据,可直接使用该ID,但仍不清楚问题出在哪里。
解决方案
1. 导入ConnectionHandler工具类
首先引入Relay官方提供的Connection操作工具:
import { ConnectionHandler } from 'relay-runtime';
2. 修正updater函数实现
核心是通过ConnectionHandler定位Store中的Connection,并将订阅返回的新数据合并进去,同时注意接收订阅返回的data参数:
function updater(store, data, caseFileId) { // 1. 获取根Query节点(分页片段挂载在Query类型上) const rootQuery = store.getRoot(); // 2. 定位目标Connection:使用@connection的key + 分页查询时的变量 const connection = ConnectionHandler.getConnection( rootQuery, 'ImageViewer_files', // 与分页片段中@connection的key完全一致 { GetFilesInput: { keyName: 'CaseFileId', keyValue: caseFileId } } // 分页查询用的变量,确保匹配 ); // 3. 拿到订阅返回的新文件Connection数据 const newFilesConnection = data.monitorFiles.files; if (!connection || !newFilesConnection) return; // 4. 处理新增的edges:逐个插入到Connection末尾(可根据需求改为insertEdgeBefore) newFilesConnection.edges.forEach(newEdge => { ConnectionHandler.insertEdgeAfter(connection, newEdge); }); // 5. 更新Connection的pageInfo和totalCount connection.setValue(newFilesConnection.pageInfo.endCursor, 'pageInfo', 'endCursor'); connection.setValue(newFilesConnection.pageInfo.hasNextPage, 'pageInfo', 'hasNextPage'); connection.setValue(newFilesConnection.totalCount, 'totalCount'); }
3. 调整订阅配置
确保updater能拿到所需的参数:
const subscriptionConfig = useMemo( () => ({ subscription: imageSubscription, variables: { MonitorFilesInput: { keyName: 'CaseFileId', keyValue: `${caseFileId}`, }, }, // 传递store、订阅数据和caseFileId给updater updater: (store, data) => updater(store, data, caseFileId), }), [caseFileId, imageSubscription] ); useSubscription<any>(subscriptionConfig);
关键注意事项
- 确保订阅返回的
edge结构与分页查询的edge完全一致,包括cursor和node的所有字段,否则Relay无法正确合并数据 - 如果需要处理删除操作,可使用
ConnectionHandler.deleteNode(connection, nodeId)或ConnectionHandler.removeEdge(connection, edge) - 若订阅返回的是全量Connection数据而非增量,可直接覆盖Connection的
edges字段,但推荐增量更新以保证性能
内容的提问来源于stack exchange,提问作者Adam Jones
相关产品推荐
相关产品推荐

