Flutter 中的服务端状态
服务端数据需要的是缓存,而不是另一个状态类:缓存为每个界面提供同一份数据,跟踪加载和错误,并刷新已经过时的数据。
Flutter 应用显示的大部分内容来自服务器:待办事项列表、个人资料、一页搜索结果。这些数据的表现与应用自己拥有的状态不同:
- 应用并不拥有它。它在服务器上变化,不会通知应用。
- 它是共享的。多个界面显示同一个列表,它们应该保持一致。
- 它来得晚,或者根本不来。每次读取都有加载状态和错误状态。
- 它会过时。1 分钟前获取的列表,现在可能已经不对了。
应用状态(例如选中了哪个标签页)没有这些问题:
| 应用状态 | 服务端数据 | |
|---|---|---|
| 谁更改它 | 你的代码 | 服务器,随时都可能 |
| 谁掌握真实数据 | 应用 | 别处 |
| 何时到达 | 立即 | 稍后,或者永远不到 |
| 是否会过时 | 否 | 是 |
如果把服务端数据和应用状态放在一起,就要自己编写缓存:仓库中的缓存、每个界面的加载标志、刷新方法、每次写入后的失效处理,以及两个界面同时请求时的规则。
缓存提供了什么
Section titled “缓存提供了什么”Fuery 把服务端数据按键保存在一个缓存中:
final todosQuery = Query( queryKey: ['todos'], queryFn: (_) => api.getTodos(),);有了这一个定义:
- 每个键一份数据。使用
['todos']的所有界面读取同一个缓存条目(CachedQuery)。 - 同一时间只有一个请求。在获取进行中请求数据的界面共享这个请求。
- 先新鲜,后过期。数据在
staleTime(默认值:0,因此数据一到达就过期)内保持新鲜。 - 旧数据留在屏幕上。Fuery 在后台重新获取时,界面继续显示旧数据。
- 自动重新获取。界面开始使用过期数据时,以及应用回到前台时,Fuery 重新获取这些数据。接入网络状态来源后,Fuery 还会在网络重新连接时重新获取(网络重新连接时)。
- 写入后重新获取。变更后使
['todos']失效,就会重新获取屏幕上的列表。 - 加载和错误随数据一起提供。结果带有
status、error以及isRefetching等标志,因此界面直接读取它们,无须自己跟踪。 - 未使用的数据从内存中移除。没有界面使用数据时,Fuery 在垃圾回收时间(
gcTime,默认值:5 分钟)过后移除它。持久化的数据仍保留在设备上。
查询生命周期列出缓存数据的每个阶段,以及结束每个阶段的条件。
缓存在哪里运行
Section titled “缓存在哪里运行”缓存是一个普通的 Dart 对象,不属于 widget 树。同一个查询可以用在三个地方:
QueryBuilder渲染它;- cubit 监听
todosQuery.observe()的stream; - 脚本用
await等待client.query(todosQuery)。
Fuery 不会取代你已经在用的状态管理方案。Bloc 和 cubit 展示如何在 cubit 和 bloc 中使用查询。