ApolloClient v3 fetchMore 带有嵌套查询结果

don*_*ntc 5 apollo reactjs graphql apollo-client github-graphql

我正在使用 ApolloClient 3 GitHub GraphQL API 从存储库检索所有版本。

查询如下所示:

query ($owner: String!, $name: String!, $first: Int, $after: String, $before: String) {
  repository(owner: $owner, name: $name) {
    id
    releases(orderBy: {field: CREATED_AT, direction: DESC}, first: $first, after: $after, before: $before) {
      nodes {
        name
        publishedAt
        resourcePath
        tagName
        url
        id
        isPrerelease
        description
        descriptionHTML
      }
      totalCount
      pageInfo {
        endCursor
        hasNextPage
        hasPreviousPage
        startCursor
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

结果有效负载如下所示:

查询结果负载

这将返回前 x 个条目 ( nodes)。到目前为止,一切都很好。

我需要实现分页,并且使用fetchMoreApolloClient 提供的功能useQuery。调用fetchMore成功获取下一个 x 条目,但这些条目未显示在我的组件列表中。

根据ApolloClient Pagination 文档,似乎有必要使用ApolloClient 缓存机制来处理结果mergingfetchMore对于简单的情况,文档是可以理解的,但我正在努力为需要合并在一起的实际结果数组深深嵌套在查询结果()中的情况实现解决方案repository -> releases -> nodes

这是我对 InMemoryCache 选项合并的实现:

const inMemoryCacheOptions = {
  addTypename: true,
  typePolicies: {
    ReleaseConnection: {
      fields: {
        nodes: {
          merge(existing, incoming, options) {
            const previous = existing || []
            const results = [...previous, ...incoming]
            return results
          }
        }
      }
    },
  }
}
Run Code Online (Sandbox Code Playgroud)

这里的数组results包含完整列表,包括现有条目和新的 x 条目。这本质上是正确的结果。但是,我使用useQuery和功能的组件列表在调用fetchMore后没有获取新条目。fetchMore

我在上面的代码中尝试了各种组合inMemoryCacheOptions,但到目前为止我还没有成功。

要添加更多上下文,这是相关的组件代码:

export default function Releases() {
  const { loading, error, data, fetchMore } = useQuery(releasesQuery, {
    variables: {
      owner: "theowner",
      name: "myrepo",
      first: 15
    }
  });

  if (loading) return null;

  if (error) {
    console.error(error);
    return null;
  }

  if (data) {
    console.log(data?.repository?.releases?.pageInfo?.endCursor);
  }

  const handleFetchMore = () => {
    fetchMore({
      variables: {
        first: 15,
        after: data?.repository?.releases?.pageInfo?.endCursor
      }
    });
  };

  return (
    <div>
      <ul>
        {data?.repository?.releases?.nodes?.map(release => (
          <li key={release.id}>{release.name}</li>
        ))}
      </ul>
      <button onClick={handleFetchMore}>Fetch More</button>
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

fetchMore组件不再使用新数据重新渲染后。

如果有人有任何其他想法我可以尝试,我将不胜感激。

don*_*ntc 7

我终于设法解决了这个问题。React 组件代码没有变化,但InMemoryCacheOptions现在看起来像这样:

const inMemoryCacheOptions = {
  addTypename: true,
  typePolicies: {
    Repository: {
      fields: {
        releases: {
          keyArgs: false,
          merge(existing, incoming) {
            if (!incoming) return existing;
            if (!existing) return incoming;

            const { nodes, ...rest } = incoming;
            // We only need to merge the nodes array.
            // The rest of the fields (pagination) should always be overwritten by incoming
            let result = rest;
            result.nodes = [...existing.nodes, ...nodes];
            return result;
          }
        }
      }
    }
  }
};
Run Code Online (Sandbox Code Playgroud)

releases与原始代码相比的主要变化是我现在为类型字段定义了 typePolicy Repository。以前我试图直接进入nodes类型领域Release。由于我Repository输入了 gql 查询的根并在组件中使用,因此它现在从缓存中读取合并的结果。

如果我指定了文档中提到的 typePolicy Query,我将无法指定该releases字段的合并行为,因为它会太深一层(即Query -> repository -> releases)。这就是导致我一开始感到困惑的原因。