状态与数据流(页面加载策略、全局状态、刷新边界)

1) 快速定位

  • 全局状态定义src/state/app_state.rs
  • 状态注入src/app.rsprovide_app_state()
  • 页面数据加载src/pages/*
  • 数据访问src/db/*_repo.rs

2) AppState 的职责与边界

AppStatesrc/state/app_state.rs)包含:

  • assets: Vec<Asset>
  • snapshots: Vec<Snapshot>
  • plans: Vec<AllocationPlan>
  • active_plan: Option<AllocationPlan>
  • loading: bool
  • error: Option<String>
  • is_inventory_mode: bool(当前更多是 UI 语义,部分页面也有局部 state)

推荐理解方式:

  • 数据库是事实来源(source of truth)
  • AppState 是 UI 缓存(cache)
    • 读 DB 后写入 state,页面渲染从 state 读取
    • 写 DB 成功后刷新 state(避免脏 UI)

3) 目前的加载策略(以代码为准)

不同页面采用了不同的“初始加载”风格:

  • HistoryPage / AnalysisPage:使用 use_effect 在初始渲染时加载 DB 数据
  • HomePage:使用 loaded signal 做“一次性执行”保护,并在渲染路径中读取 DB(学习期能跑通,但工程上更推荐 use_effect)
  • AssetsPage:更多依赖 AppState.assets,并在保存/删除后触发 refresh
  • PlansPage:激活/保存/删除后重新拉取 plans 并写入 state

这说明项目仍处于“可快速迭代”的阶段,统一数据加载层(Service/Store)仍有空间。


4) 推荐的数据流模式(适合逐步演进)

4.1 最小可控模式(现阶段推荐)

  • 页面初始化:从 Repository 拉数据 → 写入 AppState
  • 发生写操作(保存/删除/激活):写 DB 成功 → 重新查询 → 写入 AppState

优点:

  • 简单可靠,不需要复杂缓存一致性策略

缺点:

  • 重复查询较多(但对个人资产规模通常足够)

4.2 进阶模式(后续可做)

  • 引入 services/* 作为业务入口:
    • 页面只调用 service
    • service 负责 DB + 校验 + 错误类型 + 刷新 state

这会显著减少页面层的重复逻辑。


5) 与所有权/借用相关的注意点(Dioxus Signal)

Signal<AppState>.read()/.write() 会持有内部借用句柄。

建议:

  • 缩小借用作用域:读完就 drop,再写
  • 必要时 clone:UI 渲染需要拥有数据(尤其跨作用域/闭包)时,用 clone 换取简单性
  • 避免在渲染路径写 state:优先 use_effect

6) 典型业务流(从入口到落库)

6.1 新增资产

  • UI:AssetsPageAssetFormsrc/pages/assets.rs / src/components/asset/asset_form.rs
  • 写库:AssetRepository::insert(&asset)
  • 刷新:AssetRepository::find_all()state.write().assets = ...

6.2 发起盘点(生成快照)

  • UI:InventoryModesrc/components/snapshot/inventory_mode.rs
  • 写库:SnapshotRepository::create(&snapshot) + 更新资产市值(若实现)
  • 刷新:重新读取 assets/snapshots 写入 state

6.3 切换激活方案

  • UI:PlansPage 触发
  • 写库:PlanRepository::set_active(plan_id)
  • 刷新:PlanRepository::find_all() → 更新 state.plans(并推导 active_plan

7) 建议的可观测性(学习期非常有帮助)

  • 把写库失败写入 state.error 并在 Layout 顶部展示(而不是只打印)
  • 对重要操作(创建快照、激活方案)记录一条可读日志(先 println!,后续可引入日志库)