GraphQL Flutter包缓存正确实现方案及有效性验证方法咨询
我之前也踩过graphql-flutter缓存的坑,官方示例的默认配置确实容易让人误以为缓存没起作用,咱们一步步来调整配置,再教你怎么验证缓存是否正常工作。
一、修正缓存的核心配置
先看你提供的客户端初始化代码,OptimisticCache本身是没问题的,但要确保几个关键配置到位:
1. 确保dataIdFromObject能生成唯一标识
你用了typenameDataIdFromObject,这个默认函数会把对象的__typename和id(或_id)拼接成唯一ID,但有些GraphQL服务返回的主键字段可能不是id(比如自定义服务用uuid)。如果你的数据主键不是id,得自定义这个函数:
String customDataIdFromObject(Object object) { if (object is Map<String, dynamic>) { final String? typename = object['__typename']; // 替换成你实际的主键字段,比如uuid、userId等 final String? id = object['id'] ?? object['uuid']; if (typename != null && id != null) { return '$typename:$id'; } } // fallback到默认实现 return typenameDataIdFromObject(object); }
然后在缓存配置里替换:
cache: OptimisticCache( dataIdFromObject: customDataIdFromObject, ),
2. 查询时指定正确的fetchPolicy
这是最容易忽略的点!默认的fetchPolicy是networkOnly——也就是每次都强制从网络拉取数据,自然不会用到缓存。你需要在Query组件或者useQuery钩子中指定合适的策略:
cacheFirst:优先用缓存,缓存没数据再请求网络(适合不需要实时更新的场景)cacheAndNetwork:先返回缓存数据,同时后台请求更新缓存(适合要快速显示+实时更新的场景)cacheOnly:只从缓存取数据(适合离线场景)
比如在Query组件里配置:
Query( options: QueryOptions( document: gql(/* 你的查询语句 */), fetchPolicy: FetchPolicy.cacheFirst, // 这是关键! ), builder: (QueryResult result, {VoidCallback? refetch, FetchMore? fetchMore}) { // 你的UI构建逻辑 }, )
也可以全局设置默认策略,避免每个查询都重复配置:
final ValueNotifier<GraphQLClient> client = ValueNotifier<GraphQLClient>( GraphQLClient( cache: OptimisticCache(...), link: link, defaultPolicies: const DefaultPolicies( query: Policies(fetch: FetchPolicy.cacheFirst), ), ), );
二、验证缓存是否生效的实用方法
1. 用调试工具查看缓存内容
开启客户端的调试模式,就能在Flutter DevTools里查看缓存数据:
GraphQLClient( cache: OptimisticCache(...), link: link, debug: true, // 开启调试模式 );
打开Flutter DevTools的「Inspect」面板,找到GraphQLProvider,就能查看缓存里存储的所有数据了。
2. 离线测试法
把设备/模拟器切换到离线模式,重新打开页面。如果能正常显示之前加载过的数据,说明缓存已经生效。
3. 打印请求日志验证
给HttpLink添加日志拦截器,看看是否真的发送了网络请求:
final HttpLink httpLink = HttpLink( uri: 'https://api.github.com/graphql', ); // 添加日志拦截 final Link loggedLink = httpLink.transform( RequestLogger( logRequest: true, logResponse: true, ), ); // 拼接链路时用loggedLink Link link = authLink.concat(loggedLink);
如果缓存生效,使用cacheFirst策略时,第二次加载页面不会打印新的网络请求日志。
三、针对官方示例的额外注意点
如果官方示例里开启了ENABLE_WEBSOCKETS,WebSocketLink的默认策略可能会影响缓存,你可以给WebSocketLink单独设置策略,或者确保查询时的fetchPolicy优先级更高。另外,记得替换示例中的YOUR_TOKEN为有效的GitHub个人访问令牌,避免因请求失败误以为缓存没生效。
内容的提问来源于stack exchange,提问作者awaik

