2021 年的 Flutter 状态管理:如何选择?


原文链接:Flutter State Management in 2021: When to Use What? | by Anthony Oleinik | Level Up Coding

有时候选择比较少也是一件好事,例如在 React 中通常只盛行一到两个状态管理解决方案,而 Flutter 自从 2020 年末开始,每个月似乎都有新的状态管理方案出现,因此这里主要罗列出它们的一些优劣,从而帮助你选择最适合的状态管理方案。

基础

一般在无需修改 pubspec.yaml 文件的情况下,你默认有两种状态管理解决方案可以选择,大多数时候这就足够了。

setState

setState 仅在本地范围内有效,如果一个 Widget 需要改变它自己的状态,那么 setState 就是你最好的选择。

例如:修改开关是打开还是关闭,或者存储改变正在输入的文本内容,「这种场景你真的不需要考虑任何其它状态管理包」

我的经验法则是:「如果只在此 Widget 中需要有状态变量,或者在该控件树下恰好只有 1 个上下的 Widget,则它属于本地范围,这时候直接使用 StatefulWidget 是最合适不过。」

如果你需要将状态在控件树内向下传递树,那么只需将变量放在子 Widget 的构造函数中;如果相同的变量需要传递到 2+ Widget 的构造函数,那么这时候才需要研究更高范围的状态管理。

InheretedWidget

前面我们在 setState 中讨论的那个开关,如果它是控制应用是处于暗模式还是亮模式,如果在这种情况下,你就需要将状态提升到可以更好地沿控件树传播的某个位置。

而在你使用第三方框架去完成这个需求时,让我们看一下 InheretedWidget

InheretedWidget 允许它下面的任何 Widget 访问它的属性,这意味着可以有一个变量,例如:

enum Theme {
  dark,
  light 
}

InheretedWidget 内部,任何与主题有关的 Widget 都可以通过 MyInheretedWidget.of(context).theme 访问主题,并且该 Widget 还会在主题更新时自动重建。

直接使用 InheretedWidget 不好的地方在于会有很多样板,Widget 系统有大量重复的代码。


你需要安装的那些

BLoC (Cubit?)

Bloc 可能是 Flutter 中状态管理最古老的解决方案之一(不考虑 scoped_model 的话),并且现在看来仍然还不错。

最近 BLoC 已将 Cubit 添加到组合中,这使得 BLoC 或多或少不会显得过气,因为 Cubit 降低了所需的样板,这意味着以后迁移更容易,而在我看来 BLoC 在这两个不同的领域中表现出色:

1、与团队合作

BLoC不灵活 方面做得非常好,可能对于很多人来说这是一件坏事:他们希望能更快速地更改他们的应用,而无需编写或更改太多代码。

但是对于团队来说情况并非如此:通过让事情变得不灵活,你可以保证一切都按照最初开发人员的预期工作——例如 BLoC 中的状态仅仅有 1、2 和 3 这样的值,你在使用 BLoC 更改为这些值时,其他程序员不会意外地将其值移动到 4,这就是它不灵活的好处。

1、事件驱动状态

BLoC 是基于事件驱动的,你必须定义你的事件,执行 API 调用可能会触发一个事件,该事件会推出一个 CallingAPIState 的 state,然后当 API 调用完成时,它会推出一个 HaveAPIResultsState .

「如果你想严格定义你的事件和状态,那么 BLoC 很适合你,如果你需要灵活性和开发速度,那么 BLoC 可能不是正确的选择。」


Provider

出于遗留原因这里将 Provider 列入介绍,它很简单,很干净,很棒……但有一些缺陷和改进的余地。

Provider 视为 InheretedWidget 使用可以减少样板文件,事实上 Provider 是建立在 InheretedWidget 之上,它只是减少了你需要编写的代码量。

如果你的应用已经在使用 Provider ,那么你可以继续使用它,这是一个非常好的状态管理包,没有理由需要迁移到另一个解决方案。

但是它还有一些改进的余地,我认为 RiverPodProvider 有改进余地的地方做得更好」


RiverPod

RiverPod 的网站上可以看到,他们称自己为“Provider,但与众不同”。

这样的形容很贴切,Provider 即使削减了很多的模版,但仍然有一些是可以进一步减少的。此外 Provider 依赖于 BuildContext ——我认为在很多情况下这确实很棒(它会迫使你使用 Widget 树),但有时就像应用的生命周期一样,在任何的地方获取 BuildContext 是不切实际的。

RiverPodProvider 的优点上改进如下:

  • 「比 Provider 更少的样板」:RiverPod 在减少 Provider 模版方面做得很好,允许开发者只注册一个顶级存储而不必单独提供每个提供。(可能有人一想到把所有东西都集中在一个地方而畏缩——别担心,你可以确定你的 pod。)
  • 不依赖 BuildContext:这也是一个很好的选择,原因前面已经提到。有时你只是无法在需要的地方获得 BuildContext。
  • 「编译安全」:到目前为止这是状态管理的最佳创新,只要代码能编译就是安全的,我们不再需要知道为什么不能在树中找到我们的 Provider , 这是一项巨大的创新,可以为你节省很多的时间。
    RiverPod 只是 Provider 的不同皮肤——但是它是更光滑、更好的皮肤,如果您正在启动一个新应用并想使用 Provider ,我强烈建议你考虑 RiverPod

其他

以下是在考虑状态管理的时候调研过的方案,但最终没有使用:

  • GetX :我不是 GetX 的粉丝,GetX 试图完成很多工作,但这限制了你的灵活性,如果你希望有“完整应用场景” 的第三方包,那么 GetX 是你的最佳选择没,我对此尝试过接入,但不喜欢它。

  • get_itget_it 不是一种状态管理方案——但大家一直在使用它,如果用作状态管理方案来看,它会非常混乱。

  • redux / fish_redux / mobx:这些都来自 React ,并且具有非常相似的风格——但我认为 ReactFlutter 是两个看起来相似却不同的框架,如果你习惯了它们,那么你可以使用它们,但在我看来,为 Flutter 设计的状态管理框架更为干净。

推荐阅读
相关专栏
前端与跨平台
90 文章
本专栏仅用于分享音视频相关的技术文章,与其他开发者和声网 研发团队交流、分享行业前沿技术、资讯。发帖前,请参考「社区发帖指南」,方便您更好的展示所发表的文章和内容。