fish-redux 组件刷新控制指南:ShouldUpdate 原理、默认行为与自定义实现
发布时间:2026/10/10 5:58:24 锦皓数字建站

前端【免费下载链接】fish-reduxAn assembled flutter application framework.项目地址https://gitcode.com/gh_mirrors/fi/fish-redux点击查看免费下载导读fish-redux 是一个数据驱动 UI的 Flutter 应用框架当 Store 中的状态发生变化时框架会扁平化地通知所有组件。默认情况下它通过identical判断新旧状态是否为同一实例来决定是否刷新而这套判定逻辑就是ShouldUpdate。本文将结合框架源码与测试用例讲清 ShouldUpdate 的触发时机、默认策略、自定义写法与实战注意事项帮助你精确控制组件刷新避免不必要的重建提升页面性能。本文依据仓库中的官方概念文档 docs/concept/should-update.md中文版见 docs/zh-cn/concept/should-update.md并配合源码与测试进行纵深验证。一、核心机制Store 扁平化通知所有组件在 fish-redux 中状态的变更流程遵循单 Store 扁平化通知模型全局或页面级的Store维护唯一状态当dispatch一个Action后Reducer产出新状态Store 会扁平化flatly地通知所有组件而不是由开发者手动指定谁该刷新、谁不该刷新。所有组件Component、Adapter、Page共享同一份状态源。通知到达每个组件后组件内部通过ViewUpdater接口统一处理刷新逻辑。该接口定义于 lib/src/redux_component/basic.dart/// Data driven ui /// 1. How to render /// 2. When to update abstract class ViewUpdaterT { Widget buildWidget(); void didUpdateWidget(); void onNotify(); void forceUpdate(); void clearCache(); }其中onNotify()就是收到 Store 通知后的回调didUpdateWidget()则是 Widget 重建时的回调。这两个方法都会走到同一个判断点——ShouldUpdate。二、默认刷新策略identical 比较新旧状态文档明确指出默认情况下框架使用identical比较新旧两份数据来决定是否需要刷新。对应源码在 lib/src/redux_component/component.dartComponent 构造时若未显式传入shouldUpdate会自动套用默认实现_shouldUpdate shouldUpdate ?? updateByDefaultT(),而updateByDefault的实现为static ShouldUpdateK updateByDefaultK() (K _, K __) !identical(_, __);也就是说场景identical(old, now)默认判定结果Reducer 返回了新的 State 实例false!false true刷新Reducer 原地修改并在原有实例上返回true!true false不刷新这带来一个重要的实战含义fish-redux 要求 State 是不可变的、每次变更都产生新实例。仓库示例中的 State 均实现CloneableT并通过clone()产出新对象例如 example/lib/todo_list_page/state.dart。如果 Reducer 直接return state或原地修改字段那么新旧状态仍是同一实例identical为true默认策略下组件不会刷新界面也就不会更新。三、自定义 ShouldUpdate精确控制刷新扁平化通知 identical 默认比较是一种通用且安全的设计但粒度较粗。文档指出如果我们对组件的刷新有非常精确化的诉求可以自己定义一个 ShouldUpdate。ShouldUpdate的类型定义位于 lib/src/redux_component/basic.dart/// Predicate if a component should be updated when the store is changed. typedef ShouldUpdateT bool Function(T old, T now);它是一个接收旧状态、新状态两个参数、返回bool的谓词函数返回true表示需要刷新返回false表示跳过刷新。文档给出的示例原样保留bool shouldUpdate(DetailState old, DetailState now) { return old.message ! now.message; }这个例子说明当整个DetailState中只有message字段才是 UI 关心的变化点时可以只比较该字段其他字段如时间戳、日志缓存等的变化不再触发 UI 重建从而把刷新范围收敛到最小。3.1 在哪里传入 ShouldUpdateshouldUpdate是组件逻辑构造函数的命名参数可在以下位置注入Componentlib/src/redux_component/component.dartPagelib/src/redux_component/page.dartAdapter 与源适配器如测试中的 test/test_widgets/lib/source_flow_adapter/adapter.dart测试基类 TestPage / TestComponenttest/test_widgets/lib/test_base.dart3.2 框架内置的辅助策略除默认实现外Component 还提供了两个静态工厂方法lib/src/redux_component/component.dartstatic ShouldUpdateK neverUpdateK() (K _, K __) false; static ShouldUpdateK alwaysUpdateK() (K _, K __) true;neverUpdate永不刷新适合纯静态、内容不变的组件alwaysUpdate始终刷新适合需要无条件响应每次状态变化的组件updateByDefault默认策略即!identical(old, now)。四、源码级原理ShouldUpdate 在刷新链路中的位置自定义的 ShouldUpdate 会在两个关键时机被调用两者都位于 lib/src/redux_component/context.dart 的ComponentContextoverride void didUpdateWidget() { final T now state; if (shouldUpdate(_latestState, now)) { _widgetCache null; _latestState now; } } override void onNotify() { final T now state; if (shouldUpdate(_latestState, now)) { _widgetCache null; markNeedsBuild(); _latestState now; } }ComponentContext内部维护_widgetCache与_latestStateStore 通知onNotify或父级重建didUpdateWidget到达时取出最新状态now调用shouldUpdate(_latestState, now)比较判定为true时清空 Widget 缓存并触发markNeedsBuild()随后刷新_latestState判定为false时什么都不做——既不重建 Widget也不更新缓存状态。从源码结构看shouldUpdate返回false时甚至不会更新_latestState因此跳过刷新是彻底的视图、缓存、后续比较基准三方面都不会受影响。若需要绕过这一判断强制刷新可以使用Context.forceUpdate()接口见 lib/src/redux_component/basic.dart。五、测试用例验证ShouldUpdate 的实际效果仓库的 widget 测试完整验证了自定义 ShouldUpdate 的拦截行为。见 test/lib/redux_component/page_test.dart测试构造了一个forbidRefreshUI恒返回false的 ShouldUpdate 传入TestPagebool forbidRefreshUI(ToDoList old, ToDoList now) { return false; }定义见 test/test_widgets/lib/page/page.dart测试的断言逻辑验证了三个关键点点击Add后虽然 Reducer 正常执行Track 中记录onReduce但 UI 完全未刷新expect(find.text(title-mock), findsNothing)——证明 ShouldUpdate 为false时界面不重建点击mark-0等操作后列表 UI 仍保持旧内容说明拦截是全局性的Store 通知与 Reducer 依然工作状态仍在演进Track 记录onReduce只是视图层被 ShouldUpdate 隔离。而在常规路径下各测试组件使用字段级或实例级比较例如 test/test_widgets/lib/component/component.dartbool shouldUpdate(Todo old, Todo now) old ! now;它依赖Todo实现Cloneable后的值比较语义当且仅当新旧状态内容不同才刷新。六、实战建议与注意事项6.1 与 ReducerFilter 分工fish-redux 中还有另一个性能优化点ReducerFilterTlib/src/redux_component/basic.dart它决定某 Action 是否进入 Reducer 计算而 ShouldUpdate 决定状态变化后是否重建视图。两者是不同环节的过滤ReducerFilter减少计算量拦在状态产出之前ShouldUpdate减少重建量拦在视图刷新之前。两者可以组合使用测试组件中常同时配置filter与shouldUpdate如 test/test_widgets/lib/static_flow_adapter/component.dart。6.2 自定义比较的注意点比较字段要与视图绑定ShouldUpdate 只比较 UI 真正关心的字段比较项越多收益越小注意可变对象的比较语义若字段本身是集合或对象!默认比较引用而非内容需要按业务语义设计比较逻辑State 必须可克隆要让old与now成为不同的实例State 需实现CloneableTReducer 中通过clone()产生新对象否则即使自定义比较old与now也可能指向同一实例不要依赖副作用ShouldUpdate 应是无副作用的纯函数它只负责比较并给出结论。6.3 典型应用场景列表页中仅当某个字段如选中 id变化时才刷新对应行组件子组件订阅了父级大状态但只关心其中一小部分字段某些 Action如轮询心跳频繁产生状态更新但 UI 不需要跟着每次变化重建。七、小结ShouldUpdate 是 fish-redux 对组件何时刷新的精确控制点Store 扁平化通知 默认identical比较保证了开箱即用的正确性而自定义bool Function(T old, T now)则把刷新粒度下放到字段级别。理解 component.dart 中的默认实现、context.dart 中的调用时机以及测试用例 page_test.dart 展示的拦截效果即可在实际项目中安全地通过 ShouldUpdate 优化刷新性能。赞分享前端【免费下载链接】fish-reduxAn assembled flutter application framework.项目地址https://gitcode.com/gh_mirrors/fi/fish-redux点击查看免费下载相关推荐fish-redux ShouldUpdate 精讲为组件定义精确的刷新时机fish redux ShouldUpdate 精讲为组件定义精确的刷新时机 本文是 fish redux 概念系列的组成部分围绕 docs/zh cn/c前端Fish Redux 组件精确刷新机制ShouldUpdate 从入门到源码剖析Fish Redux 组件精确刷新机制ShouldUpdate 从入门到源码剖析 数据变更时Fish Redux 的 Store 会扁平化地通知页面内所有组前端fish-redux 组件刷新机制解析ShouldUpdate 与基于 identical 的精确更新策略fish redux 组件刷新机制解析ShouldUpdate 与基于 identical 的精确更新策略 本篇技术指南围绕 fish redux 中组件刷新前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。