React Apollo 在突变后更新客户端缓存

Posted

技术标签:

【中文标题】React Apollo 在突变后更新客户端缓存【英文标题】:React Apollo updating client cache after mutation 【发布时间】:2020-02-03 21:36:00 【问题描述】:

在成功执行突变后,我正在尝试更新我的 chache。这是我的查询和突变:

export const Dojo_QUERY = gql`
query Dojo($id: Int!)
  dojo(id: $id)
    id,
    name,
    logoUrl,
    location 
     id,
     city,
     country
    ,
    members
      id
    ,
    disziplines
      id,
      name
    
   
`;


export const addDiszipline_MUTATION = gql`
mutation createDisziplin($input:DisziplineInput!,$dojoId:Int!)
  createDisziplin(input:$input,dojoId:$dojoId)
    disziplin
     name,
     id
    
  
`;

还有我的突变电话:

const [createDisziplin] = useMutation(Constants.addDiszipline_MUTATION,
    
      update(cache,  data:  createDisziplin  ) 
        console.log(cache)
        const  disziplines  = cache.readQuery( query: Constants.Dojo_QUERY,variables: id);
        console.log(disziplines)
        cache.writeQuery(
        ...some update logic (craches in line above)
        );
      
    
    );

当我执行这个突变时,我得到了错误

Invariant Violation: "Can't find field dojo("id":1) on object 
  "dojo(\"id\":\"1\")": 
    "type": "id",
    "generated": false,
    "id": "DojoType:1",
    "typename": "DojoType"
  
."

在我的客户端缓存中我可以看到

datadataDojoType ...WITH ALL DATA INSIDE APPART FROM THE NEW DISZIPLINE

datadataDisziplineType THE NEW OBJECT

网络上的客户端缓存似乎存在很多混乱。不知何故,提出的解决方案都没有帮助,或者对我没有任何意义。任何帮助将不胜感激。

编辑 1: 也许这有帮助?

ROOT_QUERY: …
"dojo(\"id\":\"1\")": …​​​​​
generated: false​​​​​
id: "DojoType:1"​​​​​
type: "id"​​​​​
typename: "DojoType"​​​​​
<prototype>: Object  … ​​​​
<prototype>: Object  … 

编辑 2

我接受了 Herku 的建议并开始使用 Fragment。但是它似乎仍然不太有效。

我更新的代码:

 const [createDisziplin] = useMutation(Constants.addDiszipline_MUTATION,
    
      update(cache,  data:  createDisziplin  ) 
        console.log(cache)
        const  dojo  = cache.readFragment(
           fragment: Constants.Diszilines_FRAGMENT,
            id:"DojoType:"+id.toString());
        console.log(dojo)
      
    
    );

export const Diszilines_FRAGMENT=gql`
  fragment currentDojo on Dojo
    id,
    name,
    disziplines
      id,
      name
    
  
`;

但是console.log(dojo) 的结果仍然未定义。有什么建议吗?

【问题讨论】:

【参考方案1】:

所以我认为您的实际错误是您必须将 ID 作为字符串提供:variables: id: id.toString()。你可以看到这两行是不同的:

dojo(\"id\":1)
dojo(\"id\":\"1\")

但我强烈建议使用readFragment 而不是readQuery 并使用提供的ID 更新dojo。这也应该更新查询以及所有查询中出现的所有其他 dojo。您可以在 readFragment here 上找到文档。

另一个技巧是简单地返回整个 dojo 以响应突变。我会说人们应该少担心这一点,并且不要做太多的缓存更新,因为缓存更新是你的 API 的隐式行为,在你的类型系统中没有。可以在 disziplins 字段中找到新的 disziplin 现在已在您的前端编码。想象一下,您想在此处添加另一个步骤,其中必须先批准新的 disziplins 才能最终进入那里。如果突变返回整个道场,一个简单的后端更改就可以完成这项工作,您的客户不必知道这种行为。

【讨论】:

谢谢。我已经尝试过你所说的,但我仍然无法定义为reault。我已经用新的来源更新了我的问题(编辑 2)。我关注apollographql.com/docs/react/v2.5/advanced/fragments/… 设置片段解析器。 也许你应该在 codesandbox.io 这样的地方发布一个复制版本。现在这是一个非常“调试我的代码”的问题...... 是的,你是对的。但感谢您让我走上正轨。

以上是关于React Apollo 在突变后更新客户端缓存的主要内容,如果未能解决你的问题,请参考以下文章

突变后使用订阅和更新创建重复节点 - 使用 Apollo 客户端

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

突变后 React Apollo 客户端道具 refetchQueries

创建突变后添加到 Apollo 客户端缓存中的数组

如何在突变之前更新 apollo 缓存状态,以进行 Like、Upvote 等操作? [关闭]

如何在多个视图中处理突变后的缓存更新?