首页 > 解决方案 > Apollo 客户端在应该发出网络请求时错误地从缓存中读取

问题描述

我有一系列 Apollo 查询,其工作方式如下:

query {
  currentWebsite {
    id
    ...sub-resources
  }
}

在当前网站更改之前,此方法效果很好。这是因为 Apollo 客户端已经在缓存中有一个网站,并且会从缓存中检索第一个(并且不正确的)网站,而不是发出另一个 HTTP 请求。我相信这是因为查询不包含唯一 ID,因此它将所有currentWebsite查询视为相同。

现在我知道有很多方法可以解决这个问题。以下是我知道的方法,以及感知到的缺点:

  1. 更新 Apollo 服务器以允许接收websiteId作为输入 arg。我对此进行了测试,并且可以正常工作。不幸的是,更新 API 需要做很多工作。
  2. 将默认值更改fetchPolicy为类似cache-and-network. 这是一个快速修复,但会发出比它需要的更多的 HTTP 请求。
  3. 当网站更改时,手动使部分缓存失效。这是我最不喜欢的解决方案。
  4. 手动从缓存中读取。如果查询不存在,请useQuery使用 fieldPolicy 之类的调用network-only。这感觉非常沉重。

最终,我认为这些解决方案中的任何一个都不是我所需要的。我觉得必须有一种方法可以为 Apollo 缓存每个查询的网站 ID,以便它可以自行确定是应该从缓存中检索网站还是获取新网站。我发现 Apollo 缓存相当不透明,不知道从哪里开始!

标签: apolloapollo-clientapollo-cache-inmemory

解决方案


所以这里的技巧是编写一个自定义keyArgs函数并利用这样一个事实,即您可以拥有不传递给服务器的客户端变量:

query GetWebsiteById($websiteId: String) {
  currentWebsite {
    id
    ...sub-resources
  }
}

$websiteId在执行查询时传递您拥有的任何标头值。然后您可以在keyArgs函数中读取该变量。

const createCache = () => new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        currentWebsite: {
          keyArgs: (_, { variables }) => {
            if (variables?.websiteId == null) {
              return 'currentWebsite';
            } else {
              return `currentWebsite:${variables.websiteId}`;
            }
          }
        }
      }
    }
  }
});

现在它将使用自己唯一的 id: 、 等将每个查询存储在缓存currentWebsite:1currentWebsite:2


推荐阅读