fetchMore return 数据如何到组件?

How does fetchMore return data to the component?

我正在尝试使用 React Apollo (https://www.apollographql.com/docs/react/data/pagination/#cursor-based) 进行基于游标的分页示例,但我正在努力解决 我呈现原始数据的组件如何获得新的(附加的)数据.

这是我们获取原始数据并将其传递给组件的方式:

const { data: { comments, cursor }, loading, fetchMore } = useQuery(
    MORE_COMMENTS_QUERY
);

<Comments
      entries={comments || []}
      onLoadMore={...}
/>

我不确定 fetchMore 函数是如何工作的。

onLoadMore={() =>
        fetchMore({
          query: MORE_COMMENTS_QUERY,
          variables: { cursor: cursor },
          updateQuery: (previousResult, { fetchMoreResult }) => {
            const previousEntry = previousResult.entry;
            const newComments = fetchMoreResult.moreComments.comments;
            const newCursor = fetchMoreResult.moreComments.cursor;

            return {
              // By returning `cursor` here, we update the `fetchMore` function
              // to the new cursor.
              cursor: newCursor,
              entry: {
                // Put the new comments in the front of the list
                comments: [...newComments, ...previousEntry.comments]
              },
              __typename: previousEntry.__typename
            };
          }
        })
      }

据我了解,是的,一旦我的组件调用此 onLoadMore 函数(例如使用按钮的 onClick),它将基于新光标获取数据。

我的问题是这样的。很抱歉,如果这太简单了,我不了解一些基本的东西。

组件如何获取新数据?

我知道数据在那里,因为我控制台记录了 newComments(在我的例子中,它不是 newComments,但你明白了。)而且我看到了新数据!但是那些新的注释,它们如何返回到需要数据的组件呢?如果我再次点击该按钮,它仍然停留在与之前相同的光标上。

我在这里错过了什么?

updateQuery 函数中,您可以修改(覆盖)当前查询的结果。同时,您的组件订阅了查询并将获得新结果。让我们来玩一下:

  • 你的组件是第一次渲染,组件会订阅查询,如果有的话,会从缓存中接收当前的查询结果。如果不是,查询将开始从 GraphQL 服务器获取,并且您的组件会收到有关加载状态的通知。
  • 如果获取查询,您的组件将在结果出现后获取数据。它现在显示前 x 个结果。在缓存中为您的查询字段创建一个条目。这可能看起来像这样:
{
  "Query": {
    "cursor": "cursor1",
    "entry": { "comments": [{ ... }, { ... }] }
  }
} 

// normalised
{
  "Query": {
    "cursor": "cursor1",
    "entry": Ref("Entry:1"),
  }
  "Entry:1": {
    comments: [Ref("Comment:1"), Ref("Comment:2")],
  },
  "Comment:1": { ... },
  "Comment:2": { ... }
}
  • 用户点击加载更多,您的查询被再次获取,但带有光标值。游标告诉 API 它应该从哪个条目开始 returning 值。在我们的示例中 Comment 之后,id 2.
  • 查询结果进来,你使用updateQuery函数手动更新缓存中的查询结果。这里的想法是我们要将旧结果(列表)与新结果列表合并。我们已经获取了 2 条评论,现在我们要添加这两条新评论。您必须 return 一个结果,该结果是两个查询的组合结果。为此,我们需要更新光标值(以便我们可以再次单击“加载更多”并连接评论列表。该值已写入缓存,我们的规范化缓存现在如下所示:
{
  "Query": {
    "cursor": "cursor2",
    "entry": { "comments": [{ ... }, { ... }, { ... }, { ... }] }
  }
}

// normalised
{
  "Query": {
    "cursor": "cursor2",
    "entry": Ref("Entry:1"),
  }
  "Entry:1": {
    comments: [Ref("Comment:1"), Ref("Comment:2"), Ref("Comment:3"), Ref("Comment:4")],
  },
  "Comment:1": { ... },
  "Comment:2": { ... },
  "Comment:3": { ... },
  "Comment:4": { ... }
}
  • 由于您的组件订阅了查询,它将使用缓存中的新查询结果重新呈现!数据显示在 UI 中,因为我们合并了查询,以便组件获取新数据,就像结果首先包含所有四个评论一样。

这取决于你如何处理偏移量。我将尝试为您简化示例。

这是我使用成功的简化组件:

const PlayerStats = () => {
  const { data, loading, fetchMore } = useQuery(CUMULATIVE_STATS, {
    variables: sortVars,
  })

  const players = data.GetCumulativeStats

  const loadMore = () => {
    fetchMore({
      variables: { offset: players.length },
      updateQuery: (prevResult, { fetchMoreResult }) => {
        if (!fetchMoreResult) return prevResult
        return {
          ...prevResult,
          GetCumulativeStats: [
            ...prevResult.GetCumulativeStats,
            ...fetchMoreResult.GetCumulativeStats,
          ],
        }
      },
    })
  }

我的 CUMULATIVE_STATS 默认查询 returns 50 行。我将该结果数组的长度作为 offset 传递给我的 fetchMore 查询。所以当我用fetchMore执行CUMULATIVE_STATS时,查询的变量都是sortVarsoffset.

我在后端的解析器处理 offset,因此如果它是,例如,50,它会忽略查询的前 50 个结果,returns 从那里开始的下一个 50(即第 51-100 行)。

然后在 updateQuery 中我有两个对象可用:prevResultfetchMoreResult。在这一点上,我只是使用扩展运算符将它们组合起来。如果没有新的结果被 returned,我 return 以前的结果。

当我再取一次的时候,players.length的结果就变成了100,而不是50。这就是我的新偏移量,下次调用fetchMore的时候会查询到新的数据。