【问题标题】:How does fetchMore return data to the component?fetchMore 是如何向组件返回数据的?
【发布时间】:2020-10-14 21:53:21
【问题描述】:

我正在尝试使用 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(在我的情况下,它不是新评论,但你明白了。)我看到了新数据!但是那些新的 cmets,它们是如何返回到需要数据的组件的呢?如果我再次单击该按钮,它仍然停留在与以前相同的光标上。

我在这里错过了什么?

【问题讨论】:

    标签: javascript reactjs graphql apollo react-apollo


    【解决方案1】:

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

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

    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 查询默认返回 50 行。我将该结果数组的长度作为offset 传递给我的fetchMore 查询。所以当我用fetchMore执行CUMULATIVE_STATS时,查询的变量都是sortVarsoffset

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

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

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

    【讨论】:

      【解决方案2】:

      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 它应该从哪个条目开始返回值。在我们的示例中,在 Comment 之后,ID 为 2
      • 查询结果进来,你使用updateQuery函数手动更新缓存中的查询结果。这里的想法是我们希望将旧结果(列表)与新结果列表合并。我们已经获取了 2 个 cmets,现在我们要添加两个新 cmets。您必须返回一个结果,该结果是两个查询的组合结果。为此,我们需要更新游标值(以便我们可以再次单击“加载更多”并连接 cmets 列表。该值被写入缓存,我们的标准化缓存现在看起来像这样:
      {
        "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 中是因为我们合并了查询,以便组件获取新数据,就好像结果首先包含所有四个 cmets。

      【讨论】:

      • 我明白我做错了什么。我没有以与原始数据完全相同的形状/格式返回数据。我忘记了__typename
      猜你喜欢
      • 2019-11-26
      • 1970-01-01
      • 2019-06-10
      • 2021-03-08
      • 2020-04-13
      • 2021-01-06
      • 2019-06-20
      • 2022-07-23
      • 2016-07-29
      相关资源
      最近更新 更多