在Flutter中管理应用程序状态

哈Ha! 提出本文的译文, 让我帮助您了解和选择适合您应用的状态管理解决方案 ,这引起了我的注意,并对在Flutter中学习状态管理基础知识的过程产生了兴趣。 我很高兴听到对此翻译有任何批评。 我的个人想法和解释将写在反引号(``)中。


颤振状态管理是一个热门话题。 有许多可能的解决方案,对它们感到困惑,选择最适合您的需求非常简单。 我自己很困惑,但是找到了合适的解决方案。 让我与您分享。

为了找到适合您需求的解决方案,您需要自己确定需求。 就我而言,这是:

  • 有机会在不影响代码质量的情况下开发项目
  • 将显示逻辑与业务逻辑分开
  • 有清晰的代码,很难破解
  • 代码的可预测性和可理解性

鉴于这些要求,合适的选项仍然存在:

  • 使用setState()方法和有状态小部件
  • `Library`范围模型
  • 使用BLoC模式(业务逻辑组件)
  • Redux

本地状态和全局状态之间的区别


在深入分析选定解决方案之前,您需要了解本地状态和全局状态之间的区别。 一个实际的例子适用于此:
想象一下授权表单,在该表单中,提示用户输入用户名和密码,并在发送表单后获取对象“用户身份”。 在此示例中,对在表单字段中输入的数据进行的任何验证都将是“授权表单小部件”的本地状态的一部分,并且应用程序的其余部分不应意识到这一点。 “授权服务器”返回的“身份”对象是全局状态的一部分。 因此,其他组件依赖于此对象,并根据用户是否被授权来更改行为。

对于那些厌倦了等待的人的简要结论
如果您不想等待,或者对我的研究不感兴趣,那么这里是结果的简要概述:


我的建议是使用BLoC进行本地状态管理,并使用Redux进行全局状态,尤其是当您要构建随时间增长的复杂应用程序时。


为什么不应该使用setState()


在小部件内部使用setState()非常适合快速进行原型制作并获得有关这些更改的反馈,但是这种方式并不能帮助我们实现目标,因为显示逻辑与业务逻辑混合在一起,这违反了代码整洁和质量原则。 将来,此类代码的维护将很困难,因此,除创建原型外,不建议使用此方法。

ScopedModel-朝正确方向迈出的一步


ScopedModelBrian Egan的第三方库。 这样就可以创建特殊的Models对象,并在必要时使用notifyListeners()方法。 例如,要跟踪模型对象属性的任何变化:

 class CounterModel extends Model { int _counter = 0; int get counter = _counter; void increment() { _counter++; notifyListeners(); } } 

在我们的小部件中,我们将能够使用此库提供的ScopedModelDescendant小部件来响应模型中的更改:

 class CounterApp extends StatelessWidget { @override Widget build(BuildContext context) { return new ScopedModel<CounterModel>( model: new CounterModel(), child: new Column(children: [ new ScopedModelDescendant<CounterModel>( builder: (context, child, model) => new Text('${model.counter}'), ), new Text(" ,     CounterModel") ]) ); } } 

与使用setState()方法相反,此解决方案允许您将显示逻辑与业务逻辑分开。 但是,它施加了某些限制:

  • 如果Model变得复杂,那么很难确定何时使用notifyListeners()方法,以及何时不使用以避免避免不必要的接口更新。
  • 通常, Model提供的API无法准确描述应用程序接口的异步性质

考虑到所有这些,如果您的应用程序状态不容易管理,我不建议您使用这种数据方法。 我只是不相信他能够有效地提供应用程序的增长和复杂性。

强大的解决方案-BLoC


这种模式是由Google发明的,并且也在其中使用。 他将帮助我们实现以下目标:

  • 显示逻辑与业务逻辑的分离
  • 使用异步特性显示接口
  • 具有在不同的Dart应用程序(例如Flutter或AngularDart)中重用的能力

这种方法背后的想法非常简单:

  • BLoC用途
     Sink<T> 
    api描述异步输入我们的数据组件
  • BLoC用途
     Stream<T> 
    api描述我们的组件异步返回的数据
  • 最后,我们可以使用StreamBuilder小部件来控制数据流,而无需费力地订阅数据更新和重绘小部件

Google有使用这种状态管理模式的很好的例子,因为它已被公司广泛使用并受到公司的强烈推荐。

我本人强烈建议使用这种方法来管理本地状态,但是它甚至适合于管理全局状态。 但是,在后一种情况下,您将遇到一个问题-在何处以及如何正确实现BLoC,以便不同的组件可以访问它,然后Redux进入现场。

Redux和BLoC-对我而言是完美的组合


我在本文开头描述的目标之一就是找到一种被广泛使用和可预测的东西,这就是Redux-一种模式和一组工具,可以共同帮助我们管理全球状态。 它的核心是三个基本原则:

唯一的事实来源是应用程序state的整个状态都存储在单个存储中的树对象中

  • 状态是只读的-更改状态的唯一方法是调用描述该状态应该发生什么的特殊操作对象
  • 使用纯函数进行更改-要确定状态的变化,请编写纯的reducer函数,该函数不应引起任何副作用链接到示例代码。


链接到原始帖子,图像来自

这种状态管理方法已被Web开发人员广泛接受,并且它在移动设备上的出现将有助于获得Web和移动应用程序开发人员的利益。

Brian Egan正在开发原始Reduxflutter_redux ,并且还制作了一个很棒的Todo应用程序 ,其中应用了许多架构模式,包括Redux。
考虑到Redux的所有特性,我强烈建议使用它来管理全局状态,但是如果要扩展应用程序,应确保不要使用它来管理本地状态。

最后的话


本文没有完全正确或不正确的解决方案。 要决定在项目中应用哪种方法,您需要决定自己的需求。 就我和我的目标而言,Redux和BLoC的结合使我的项目能够快速安全地增长,而且借助易于访问且清晰的工具,第三方开发人员也可以更轻松地进入这些项目。 但是,并非每个人都有相同的需求,并且随着时间的流逝,您会发现“当前工具”中的两个问题以及更好的解决方案。 始终保持好奇心,学习和思考该工具是否适合您非常重要。

Source: https://habr.com/ru/post/zh-CN435780/


All Articles