Skip to content

3.1.6 Riverpod 架构优化与 Bug 修复 - #2

Merged
dorkytiger merged 16 commits into
mainfrom
3.1.6
Aug 3, 2026
Merged

3.1.6 Riverpod 架构优化与 Bug 修复#2
dorkytiger merged 16 commits into
mainfrom
3.1.6

Conversation

@dorkytiger

Copy link
Copy Markdown
Owner

Riverpod 架构优化与 Bug 修复

概述

本次优化聚焦于 Riverpod provider 架构的正确性,修复了多个导致"数据重复加载"、"provider 被意外 dispose"、"表单校验不生效"的核心问题,统一了 provider 的使用模式。


核心问题与修复

1. 数据与 UI 状态分离

问题BookList.build() 同时 watch 了数据源和 UI 状态(选择模式、布局、选中项),导致每次勾选/切换布局都触发整个列表数据重新加载。

修复

  • BookList.build() 移除 ref.watch(bookListUiProvider),只 watch 数据源和查询条件
  • View 层直接 ref.watch(bookListUiProvider) 获取 UI 状态
  • deleteSelected()bookListUiProvider 读取 selectedBookIds

涉及文件

  • lib/feature/book/ui/provider/book_provider.dart
  • lib/feature/book/ui/view/book_list_view.dart

2. FSelectTileGroup 多选修复

问题:使用 FMultiValueControl.managedRadio()(单选)而非 managed()(多选),且未传 initial 导致选中状态丢失。

修复

  • 改为 FMultiValueControl<int>.managed(initial: selectedIds, ...)
  • selectedIdsbookListUiProvider 实时获取

涉及文件

  • lib/feature/book/ui/view/book_list_view.dart

3. Family 参数稳定性

问题:在 build() 中每次创建新的 List<int> 作为 family 参数,Dart List 使用引用比较,导致 Riverpod 认为是不同参数 → 旧 provider dispose → 新 provider 创建 → 异步操作中断。

修复:将 family 参数在 initState() 中创建一次,存为 late final 字段。

涉及文件

  • lib/feature/export/ui/view/export_batch_form_view.dart_bookIds
  • lib/feature/parse/ui/view/parse_batch_pdf_view.dart_param

4. Provider build() 生命周期

问题build() 使用 Future.microtask() 异步启动工作并立即返回空数据,导致:

  • 初始瞬间显示"暂无内容"而非 loading
  • 手动 state = AsyncLoading() 与 Riverpod 自动状态管理冲突

修复:将解析逻辑直接放入 build()await,Riverpod 自动管理 loading/data/error 状态。删除所有手动 state = AsyncLoading() / AsyncData() / AsyncError() 调用。

涉及文件

  • lib/feature/parse/ui/provider/parse_batch_archive_provider.dart
  • lib/feature/parse/ui/provider/parse_batch_pdf_provider.dart

5. Export Provider 防 Dispose

问题ExportBatch.build() 使用 ref.watch(bookListProvider),书籍列表任何变化都导致 export provider 重建/dispose,doExport() 异步操作被中断。

修复

  • build() 改用 ref.read(bookListProvider)
  • doExport() 在每个 await 后和回调中加 ref.mounted 守卫

涉及文件

  • lib/feature/export/ui/provider/export_batch_provider.dart
  • lib/feature/export/ui/provider/export_single_provider.dart

6. GlobalKey 放置

问题GlobalKey<FormState>build() 中创建(ConsumerWidget),每次 rebuild 都生成新 key,currentState 永远为 null,表单校验失效。

修复:将 view 改为 ConsumerStatefulWidget_formKey 放在 State 中。

涉及文件

  • lib/feature/export/ui/view/export_single_form_view.dart
  • lib/feature/export/ui/view/export_batch_form_view.dart

7. readOnly 字段与 Form 校验

问题readOnly: trueFTextFormField 不参与 Form 的 value 追踪,validate() 始终返回 false 但不显示错误,导致"点击无反应"。

修复:readOnly 字段不设 validator,在按钮 onPress 中手动检查 controller 值。

涉及文件

  • lib/feature/export/ui/view/export_batch_form_view.dart

8. showFToast context 失效

问题:删除书籍后 widget 被移除,原 context 失效,调用 showFToast 报错 "Looking up a deactivated widget's ancestor is unsafe"。

修复:在异步操作前保存 Navigator.of(context).context(Navigator 级 context,不受 tile 删除影响)。

涉及文件

  • lib/feature/book/ui/view/book_list_view.dart(3 处)

9. 保存进度 total 始终为 0

问题saveBatchAsBook() 的回调只更新 current,从未设置 total

修复:在 await 前初始化 progress provider,设置 total: parseBatchList.length

涉及文件

  • lib/feature/parse/ui/provider/parse_batch_pdf_provider.dart

关键模式总结

场景 正确做法
Provider 读其他 provider 数据 ref.read 避免级联重建
Family 参数含 List initState() 创建一次,不要每次 build 新建
async provider 的 build() 直接 await 工作,让 Riverpod 管理 loading/data/error
GlobalKey 放在 ConsumerStatefulWidgetState
异步操作后 showFToast 提前保存 Navigator.of(context).context
异步操作后操作 state 检查 ref.mounted(provider)/ context.mounted(widget)
readOnly 表单字段 不用 validator,手动检查 controller

@dorkytiger
dorkytiger merged commit 5d04027 into main Aug 3, 2026
0 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants