当变量发生变化时,Apollo 客户端缓存不会在查询中更新

Posted

技术标签:

【中文标题】当变量发生变化时,Apollo 客户端缓存不会在查询中更新【英文标题】:Apollo Client cache doesn't update on query when variables are changing 【发布时间】:2021-06-10 16:57:22 【问题描述】:

我对 Next、GraphQL 和 Apollo 完全陌生。我正在开发一个 twitter-clone 来练习。

索引页面显示包含所有新帖子的用户提要。我正在执行一个查询,该查询返回一个包含帖子和布尔值的对象“PaginatedPosts”,如果有更多帖子要获取(决定“加载更多帖子”按钮是否应该可见)。

如果您点击帖子的创建者(用户),您将进入一个页面(例如:/user/8),其中包含用户的个人资料和他的所有帖子。我在服务器端加载此页面,以获得更好的 SEO。我从 url 获取用户 ID,然后我进行查询以获取用户,然后我进行另一个查询以获取他的帖子,其中包含一个带有他的 ID 的变量。

现在我的问题是,如果我转到用户的个人资料,查询会被 apollo 缓存,很酷。当我访问另一个用户的个人资料时,显示给我的帖子来自前一个用户(来自缓存)。我尝试添加fetch-policy: no-cache,但如果我喜欢帖子,缓存不会自动更新。不过这看起来很奇怪,因为显示在用户个人资料页面顶部的用户会正常更改。

这是我在前端用户页面上使用的代码:

const 
    data: postsData,
    loading: postsLoading,
    fetchMore: fetchMorePosts,
    variables: postsVariables,
 = useUserPostsQuery(
    notifyOnNetworkStatusChange: true,
    skip: !userData?.user, // skip if no user id
    variables: 
      limit: 15,
      userId: userData?.user?.id || -1,
    ,
);

创建 apollo 客户端函数:

const createApolloClient = (ctx: any) => 
  let cookie = "";
  if (isServer() && ctx) 
    cookie = ctx.req.headers.cookie;
  

  return new ApolloClient(
    uri: "http://localhost:4000/graphql",
    credentials: "include",
    headers: 
      cookie,
    ,
    cache: new InMemoryCache(
      typePolicies: 
        Query: 
          fields: 
            posts: 
              keyArgs: [],
              merge(
                existing: PaginatedPosts | undefined,
                incoming: PaginatedPosts
              ): PaginatedPosts 
                return 
                  ...incoming,
                  posts: [...(existing?.posts || []), ...incoming.posts],
                ;
              ,
            ,
            userPosts: 
              keyArgs: [],
              merge(
                existing: PaginatedPosts | undefined,
                incoming: PaginatedPosts
              ): PaginatedPosts 
                return 
                  ...incoming,
                  posts: [...(existing?.posts || []), ...incoming.posts],
                ;
              ,
            ,
          ,
        ,
      ,
    ),
  );
;

如果您需要更多信息,请告诉我。

【问题讨论】:

【参考方案1】:

我最终将 userId 添加到 keyArgs(在创建 apollo 客户端函数中)。 像这样:

const createApolloClient = (ctx: any) => 
  let cookie = "";
  if (isServer() && ctx) 
    cookie = ctx.req.headers.cookie;
  

  return new ApolloClient(
    uri: "http://localhost:4000/graphql",
    credentials: "include",
    headers: 
      cookie,
    ,
    cache: new InMemoryCache(
      typePolicies: 
        Query: 
          fields: 
            posts: 
              keyArgs: [],
              merge(
                existing: PaginatedPosts | undefined,
                incoming: PaginatedPosts
              ): PaginatedPosts 
                return 
                  ...incoming,
                  posts: [...(existing?.posts || []), ...incoming.posts],
                ;
              ,
            ,
            userPosts: 
              keyArgs: ["userId"], // right there
              merge(
                existing: PaginatedPosts | undefined,
                incoming: PaginatedPosts
              ): PaginatedPosts 
                return 
                  ...incoming,
                  posts: [...(existing?.posts || []), ...incoming.posts],
                ;
              ,
            ,
          ,
        ,
      ,
    ),
  );
;

【讨论】:

以上是关于当变量发生变化时,Apollo 客户端缓存不会在查询中更新的主要内容,如果未能解决你的问题,请参考以下文章

为啥当我追加到其中的列表时,元组的内容会发生变化,但在更新变量时不会发生变化?

由于 Meteor 升级到 0.8.0,当 Session 变量依赖发生变化时,不会触发模板“rendered”回调

写入缓存时,Apollo 客户端链接状态“ 中缺少字段”?

Apollo 客户端:缓存更新后组件不呈现(反应变量)

当实际数据发生变化时,结果缓存数据会发生啥变化?

如何在 Apollo / GraphQL 发生突变后更新缓存?