使用 fetchMore 获取组件安装上的所有数据

Using fetchMore to fetch ALL data on component mount

我有一种情况需要获取例如安装组件时用户发布的所有文章。要获取用户的文章,我使用以下查询:

const GET_USER_ARTICLES = gql`
    query getUserArticles($id: ID, $numArticles: Int!, $cursor: String) {
        user(id: $id) {
            id
            articles(first: $numArticles, after: $cursor, orderBy: "-created", state: "enabled") @connection(key: "userArticles") {
                edges {
                    node {
                        name
                    }
                }
                pageInfo {
                    endCursor
                    hasNextPage
                }
            }
        }
    }
`;

如果有下一页,我想继续获取更多文章,直到我拥有所有文章。到目前为止,我还不需要做这样的事情(例如,通常我有一个按钮,用户可以单击 "Load more" 来获取更多文章,但现在需要在用户不与任何东西交互的情况下获取所有内容) , 所以我不确定最好的方法是什么。

React 中的查询示例:

const PAGE_SIZE = 10;

const { data, loading, fetchMore } = useQuery<UserArticlesData, UserArticlesVariables>(
    GET_USER_ARTICLES,
    { variables: { id: userId, numArticles: PAGE_SIZE, cursor: null } },
);

我有点迷茫如何使用 fetchMore 继续抓取直到没有更多页面,同时还向用户显示加载状态。我也不确定这是否是解决此问题的最佳方法,因此非常欢迎任何建议!

如果API不限制页面大小,您可以只提供任意大的数字作为页面大小以获得剩余结果。不过,假设页面大小只能这么大,您可以这样做:

const { data, loading, fetchMore } = useQuery(GET_USER_ARTICLES, {
  variables: { id: userId, numArticles: PAGE_SIZE, cursor: null },
  notifyOnNetworkStatusChange: true,
})
const fetchRest = async () => {
  const { user: { articles: { pageInfo } } } = data
  const updateQuery = (prev, { fetchMoreResult }) => {
    // Merge the fetchMoreResult and return the combined result
  }

  let hasNextPage = pageInfo.hasNextPage
  let cursor = pageInfo. endCursor

  while (hasNextPage) {
    const { data } = await fetchMore({
      variables: { id: userId, numArticles: PAGE_SIZE, cursor },
      updateQuery,
    })
    const { user: { articles: { pageInfo } } } = data
    hasNextPage = pageInfo.hasNextPage
    cursor = pageInfo. endCursor
  }
}

通过将 notifyOnNetworkStatusChange 设置为 true,只要 fetchMore 进行任何提取,loading 就会更新。然后我们循环直到 hasNextPage 被调用。 fetchMore returns 解析为查询结果的 Promise,因此我们可以在 updateQuery 函数之外使用查询响应。

请注意,这是一个粗略的示例——例如,您实际上可能想要自己跟踪加载状态。如果您的 API 有速率限制,您的逻辑也应该考虑到这一点。但是希望这能给你一个好的起点。

编辑:

如果您需要一开始就获取所有文章,我根本不会使用 useQueryfetchMore。最简单的解决方法是自己管理数据和加载状态并改用 client.query

const client = useApolloClient()
const [data, setData] = useState()
const [loading, setLoading] = useState(true)
const fetchAll = async () => {
  let hasNextPage = true
  let cursor = null
  let allResults = null

  while (hasNextPage) {
    const { data } = await client.query(GET_USER_ARTICLES, {
      variables: { id: userId, numArticles: PAGE_SIZE, cursor },
    })

    // merge data with allResults

    hasNextPage = pageInfo.hasNextPage
    cursor = pageInfo. endCursor
  }
  setLoading(false)
  setData(allResults)
}

useEffect(() => {
  fetchAll()
}, [])