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

如何结合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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 16:24:53