Apollo Link State需定义冗余查询才生效?
嘿,我之前也碰到过这个坑!先给你说清楚背后的原因,再给你几个解决办法:
首先,正常情况下Apollo Link State确实不需要手动写Query解析器——只要你在defaults里定义了客户端状态,查询时加上@client指令,它会自动生成对应的解析逻辑,直接从cache里读取数据。那为什么你这里必须写呢?问题出在你的状态结构和查询方式的匹配上:
你在defaults里定义的groupMenuStatus是一个对象类型(包含isOpen和__typename),而且你的查询字段名和这个根状态字段名完全一样。当你直接查询groupMenuStatus @client时,Apollo默认的自动解析器没有正确处理这种“根对象字段”的读取逻辑,它可能默认期望这个字段是标量类型,所以无法正确从cache里读取你通过mutation更新后的对象,只能一直返回defaults里的初始值。
你的mutation其实已经成功把新状态写入cache了,但因为查询时没有正确的解析逻辑,读不到更新后的数据,所以看起来mutation没生效。
解决办法(选一个就行)
1. 调整查询结构,直接读取嵌套字段
最简单的方法就是在查询时明确指定要读取的嵌套字段,而不是整个对象:
query GetGroupMenuStatus { groupMenuStatus @client { isOpen } }
这样Apollo的默认解析器就能正确识别,自动从cache里读取groupMenuStatus下的isOpen字段,不需要手动写Query解析器,mutation也能正常生效。
2. 修改状态结构,改用标量字段
如果你的状态不需要复杂的对象结构,可以直接把isOpen作为根字段:
defaults: { groupMenuIsOpen: false, // 直接用标量字段 }
mutation里改成:
updateGroupMenuStatus: (_, { isOpen }, { cache }) => { const data = { groupMenuIsOpen: isOpen, }; cache.writeData({ data }); return null; },
查询时直接写:
query GetGroupMenuStatus { groupMenuIsOpen @client }
这样完全不需要手动写任何解析器,Apollo会自动处理一切。
3. 简化你的Query解析器(如果要保留原结构)
如果你坚持要保持原有的对象结构,也可以简化手动的Query解析器,不需要写完整的gql查询:
Query: { groupMenuStatus: (_, args, { cache }) => { // 直接从cache里读取根字段 return cache.readQuery({ query: gql`{ groupMenuStatus @client }` }).groupMenuStatus; }, }
甚至更简洁:
Query: { groupMenuStatus: (_, args, { cache }) => cache.extract().groupMenuStatus, }
总结
本质上是Apollo Link State的默认解析器对“根对象类型状态”的支持不够完善,导致必须手动补充读取逻辑。只要调整查询或状态结构,就能去掉冗余的Query解析器啦!
内容的提问来源于stack exchange,提问作者Evanss

