Flutter状态管理
Flutter 中的状态管理是一个热门话题。为了选择适合需求的解决方案,实际上要做的第一件事就是明确这些需求,并设定一些目标。基于自身需求,我确定了这些:
- 在不牺牲代码质量的情况下实现稳定的开发速度
- 将展示逻辑与业务逻辑分开
- 便于理解;结构层次明确。
- 具备普适性,满足绝大部分场景
考虑到这些限制,我们将探索以下选项:
- 使用
setState()和StatefulWidgets。 - ScopedModel 范围模型
- BLoC (Business Logic Component)
- Redux
了解局部状态和全局状态之间的差异
在深入探讨各种状态管理方案之前,理解什么是本地状态和全局状态将有助于我们更好地做出选择。为此,让我们来看一个实际例子:
为了更好地理解,让我们看一个实际例子:想象一个简单的登录表单,用户可以在其中输入用户名和密码,如果数据匹配,则从后端获取 “用户” 对象。在这个例子中,任何类型的登录表单验证都可以被视为局部状态,因为这些规则的范围只适用于这个组件,而我们应用程序的其他部分并不需要知道它。然而,从后端获得的 “用户” 对象可以被视为我们全局状态的一部分,因为它改变了整个应用程序的范围(未认证 vs. 认证),并且可能其他组件也依赖于它的数据。
我的方案
我的建议是使用 BLoC 模式进行本地状态管理,并依靠 Redux 来支持全局状态范围。特别是,如果这些是会随着时间的推移而增长的复杂应用程序。
为什么不使用 setState() ?
使用Widget内部的 setState() 开发很便利,可以获得即时反馈。然而,它并不能帮助我们实现目标:表示层和业务逻辑都属于同一个类,违反了代码整洁和质量的原则。随着应用程序的增长,代码维护将来可能会成为一个挑战,
ScopedModel,朝着正确方向迈出的一步
ScopedModel 是由 Brian Egan 维护的第三方包。它允许我们创建 Model 对象,并在我们认为有必要时使用名为 notifyListeners() 的方法;例如,我们模型中的任何属性更改。
1 | class CounterModel extends Model { |
在我们的Widget中,我们可以使用 ScopedModelDescendant 对模型中的更改做出反应:
1 | class CounterApp extends StatelessWidget { |
与 setState() 相反,如果我们使用 ScopedModel 我们可以将业务逻辑与表示逻辑分开。然而,它存在一些限制:
- 如果你的
Model很复杂,那么了解何时正确调用notifyListeners()以避免不必要的更新可能会很困难。 - 公开的 API 并未准确描述一般 UI 应用程序的异步性质。
有了所有这些信息,我不建议使用 ScopedModel ,除非您的状态非常容易管理;如果您的应用程序足够复杂,我不认为这是支持这种复杂性和增长的正确答案。
BLoC,强大的解决方案
BLoC 是 Google 推出并使用的一种模式;它将帮助我们实现以下目标:
- 将业务逻辑与表示逻辑分开
- 支持UI应用的异步特性
- 可以在不同的 Dart 应用中重用,无论是 Flutter 应用还是 Angular Dart 应用。
BLoC 实现的思路非常简单:
- BLoC 公开
Sink<I>API 来描述组件的异步输入 - BLoC 公开
Stream<T>API 来描述组件的异步输出 - 最后,我们可以使用
StreamBuilderwidget来管理数据流,从而消除了维护流订阅和重绘Widget树的工作。
由于这是 Google 内部大量使用并推荐的方式,因此他们有非常好的示例,例如:https://github.com/filiph/state_experiments/tree/master/shared/lib/src/bloc_complex
建议在你的应用程序中使用 BLoC,特别是管理本地状态。即使对于全局状态管理,我相信这也可以是一个很好的解决方案;然而,您可能在这方面面临一些挑战,例如,在何处用正确的注入由不同 UI 组件访问的 BLoC,而这正是像 Redux 这样的解决方案的优势所在。
Redux 和 BLoC,完美的组合
我在文章开头描述的目标之一是寻找被广泛采用和可预测的东西。嗯,这就是 Redux。
Redux 是一种模式,结合一些工具,将帮助我们管理全局状态。它基于三个核心原则构建::
- 单一事实来源:整个应用程序的
state存储在单个store内的对象树中。 - 状态是只读的:更改状态的唯一方法是发出
action,一个描述所发生情况的对象,即action。 - 纯函数修改状态: 为了指定状态如何被 action 转换,您需要编写纯函数reducer。

基于 Redux 的所有优点,推荐将其用于管理全局状态。但是,如果你希望应用可扩展,请确保您的 Redux 架构中没有引入任何局部状态更改。
最后的想法
在选择管理状态的工具或模式时,没有绝对正确或错误的答案。最重要的是理解你的需求,选择最适合你的方案。
就我而言,结合 BLoC 和 Redux 的方式能够快速安全地扩展我的项目,同时由于这些工具在社区中广为人知,也能方便其他开发者的加入。然而,每个人的需求都不同,未来也可能会遇到问题或出现更好的工具。因此,保持好奇心,不断学习并思考什么是最适合你的解决方案才是最重要的。

