消除 Flutter 应用中的数据孤岛与复杂的失效循环
核心要点:当独立的
family提供程序将参数化的网络查询存储为孤立的状态孤岛时,更新一个子集中的实体会导致其他子集中出现陈旧数据。通过转向规范化实体存储(mapSignal)和响应式投影(computed),缓存失效、重复的网络调用以及陈旧的关系数据将完全消失。
1. 现实世界中的困境
在一个热门的 Stack Overflow 问题(#79988023)中,一位开发者在使用 Riverpod 3 family 提供程序 配合后端 REST API(例如 FastAPI/Pydantic)时遇到了常见的架构瓶颈:
列 1(计划中与进行中) ---> ref.watch(tasksProvider(Filter([planned, inProgress])))
列 2(进行中与已完成) ---> ref.watch(tasksProvider(Filter([inProgress, done])))
请注意,任务 B(inProgress)同时显示在两个列中。
两大核心痛点
-
重叠子集的不一致性:
如果用户将任务 B 从inProgress移动到done,调用patchTask(Task B)会修改后端的实体。但在前端,应该更新哪个 family 提供程序?- 仅更新列 2 会导致列 1 显示陈旧数据。
- 对所有 families 调用
ref.invalidate(tasksProvider)会强制从服务器重新获取每个过滤列表,导致冗余的网络流量和用户界面闪烁。
陈旧的关系数据:
每个Task都嵌入了一个lastEditorUser对象(User lastEditor)。如果用户 Robert 将自己重命名为 Bob,内存中的任务 A 仍然显示“Robert”,因为其嵌入的快照与用户状态更新断开连接。仅仅为了反映单个用户名的更改而重新获取每个任务查询既低效又脆弱。
2. 根本原因:作为孤立孤岛的参数化获取器
这个问题的根本原因并非 Riverpod 独有——在标准的 BLoC、Redux 或 Provider 中,每当参数化获取器同时充当本地状态容器时,都会发生这种情况。
[ Family 键: 过滤器 A ] ---> 存储 [ 任务 A, 任务 B ] (孤立孤岛 1)
[ Family 键: 过滤器 B ] ---> 存储 [ 任务 B, 任务 C ] (孤立孤岛 2)
由于 Task B 作为两个独立的、重复的对象存在于两个孤立的提供程序实例中:
- 修改孤岛 1 中的实例 B1 不会 更新孤岛 2 中的实例 B2。
- 任何一个提供程序都不知道另一个的存在。
- 开发者被迫在复杂的多提供程序变更循环与粗暴的全局缓存失效之间做出选择。
3. Signal 解决方案:规范化 + 细粒度响应性
通过从参数化状态孤岛转向响应式 Signals 架构(使用 package:signals 和 BlocSignal),问题大大简化。
不再由每个 family 提供程序管理
免责声明:本文内容来自互联网,该文观点不代表本站观点。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,请到页面底部单击反馈,一经查实,本站将立刻删除。