fetchMore 如何向组件返回数据?

a53*_*416 5 javascript apollo reactjs graphql react-apollo

我正在尝试使用 React Apollo ( https://www.apollographql.com/docs/react/data/pagination/#cursor-based )来遵循基于光标的分页示例,但我正在努力解决我的组件如何渲染原始内容的问题data 获取新的(附加的) data

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

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

<Comments
      entries={comments || []}
      onLoadMore={...}
/>
Run Code Online (Sandbox Code Playgroud)

我不确定该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
            };
          }
        })
      }
Run Code Online (Sandbox Code Playgroud)

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

我的问题是这样的。如果这太简单并且我不理解基本的东西,我很抱歉。

组件如何获取新数据?

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

我在这里缺少什么?

sli*_*den 6

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

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

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,
          ],
        }
      },
    })
  }
Run Code Online (Sandbox Code Playgroud)

我的CUMULATIVE_STATS查询默认返回 50 行。我将该结果数组的长度fetchMore作为 传递给我的查询offset。因此,当我执行CUMULATIVE_STATSwith时fetchMore,查询的变量都是sortVarsoffset

我在后端的解析器会处理该值offset,例如,如果它是 50,它会忽略查询的前 50 个结果并从那里返回接下来的 50 个结果(即第 51-100 行)。

然后在updateQuery我有两个可用的对象:prevResultfetchMoreResult。此时,我只是使用扩展运算符将它们组合起来。如果没有返回新结果,我将返回之前的结果。

当我再获取一次时,结果变为players.length100 而不是 50。这就是我的新偏移量,下次调用时将查询新数据fetchMore


Her*_*rku 5

在该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": { ... }
}
Run Code Online (Sandbox Code Playgroud)
  • 用户单击“加载更多”,您的查询将再次获取,但带有光标值。光标告诉 API 应从哪个条目开始返回值。在我们的示例中,Comment使用 id后2
  • 查询结果进来,你使用该updateQuery函数手动更新缓存中的查询结果。这里的想法是我们想要将旧结果(列表)与新结果列表合并。我们已经获取了 2 条评论,现在我们想要添加这两条新评论。您必须返回两个查询的组合结果。为此,我们需要更新光标值(以便我们可以再次单击“加载更多”并连接注释列表。该值被写入缓存,我们的规范化缓存现在如下所示:
{
  "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": { ... }
}
Run Code Online (Sandbox Code Playgroud)
  • 由于您的组件已订阅查询,因此它将使用缓存中的新查询结果重新呈现!数据显示在 UI 中,因为我们合并了查询,以便组件获取新数据,就像结果首先包含所有四个注释一样。