URQL问题:不可键化实体中的联合类型字段获取错误类型名
URQL缓存混淆不可键化联合类型的解决办法
针对你碰到的URQL在Query场景下把NumberArray错误识别成CustomNumberArray的问题,给你几个可行的解决思路:
1. 给联合类型配置自定义缓存键
虽然这些实体是不可键化的,但可以通过URQL的cacheExchange自定义每个类型的键生成逻辑,让缓存能区分不同的联合成员。创建客户端时这么配置:
import { cacheExchange } from '@urql/exchange-graphcache'; const cache = cacheExchange({ keys: { NumberArray: () => null, CustomNumberArray: () => null, // 如果需要更精准的区分,也可以结合字段生成唯一键,比如: // CustomNumberArray: (data) => `custom-${data.id}`, }, });
明确指定每个类型的键规则后,URQL就不会把不同类型的缓存条目混在一起了。
2. 在片段中显式请求__typename
URQL的GraphCache是靠__typename来区分联合类型的,而且URQL默认会自动给查询结果注入这个字段,不需要你修改Resolver。直接在片段里加上这个字段就行,完全合规:
fragment fullOption on Option { selectId type options { __typename ... on NumberArray { values } ... on CustomNumberArray { id name values } } }
这样缓存就能通过__typename准确识别每个类型的条目,不会再混淆。
3. 强制Query走网络请求
如果上面的方法都没用,可以在发起Query时指定requestPolicy: 'network-only',完全绕过缓存直接拿最新数据:
const [result] = useQuery({ query: YOUR_QUERY, requestPolicy: 'network-only', });
这个方法适合对数据实时性要求高的场景,但会牺牲缓存带来的性能优势。
4. 手动修正缓存(应急方案)
可以在Query完成后,通过cacheExchange的updates钩子或者useEffect手动调整缓存里的类型标识。比如:
const cache = cacheExchange({ updates: { Query: { // 假设你的查询字段叫getOptions getOptions: (result, args, cache) => { result.forEach(option => { option.options.forEach(item => { if (item.values && !item.id) { // 没有id的是NumberArray,手动设置__typename cache.writeFragment({ id: cache.keyOf(item), fragment: gql` fragment fixType on NumberArray { __typename } `, data: { __typename: 'NumberArray' }, }); } }); }); }, }, }, });
这个方式比较繁琐,适合临时应急用。
内容的提问来源于stack exchange,提问作者gk32001
相关产品推荐
相关产品推荐

