本文档介绍了应用状态、暂时性状态,以及如何在 Flutter 应用中管理它们。

从最广泛的意义上讲,应用的状态是指应用运行时内存中存在的一切。这包括应用的资源、Flutter 框架维护的关于 UI 的所有变量、动画状态、纹理、字体等等。虽然这种最广泛的状态定义是有效的,但对于架构应用来说并不是很有用。

首先,有些状态(如纹理)你甚至不需要管理。框架会为你处理这些。因此,一个更有用的状态定义是“你在任何时刻重建 UI 所需的任何数据”。其次,你确实需要自己管理的状态可以分为两种概念类型:暂时性状态和应用状态。

暂时性状态

#

暂时性状态(有时称为*UI 状态*或*局部状态*)是你可以在单个小部件中整齐地包含的状态。

这是一个有意模糊的定义,以下是一些例子。

  • PageView 中的当前页面
  • 复杂动画的当前进度
  • BottomNavigationBar 中当前选中的选项卡

小部件树的其他部分很少需要访问这种状态。它不需要序列化,也不会以复杂的方式改变。

换句话说,不需要对此类状态使用状态管理技术(ScopedModel、Redux 等)。你只需要一个 StatefulWidget

下面,你将看到底部导航栏中当前选定的项目如何保存在 _MyHomepageState 类的 _index 字段中。在此示例中,_index 是暂时性状态。

dart
class MyHomepage extends StatefulWidget {
  const MyHomepage({super.key});

  @override
  State<MyHomepage> createState() => _MyHomepageState();
}

class _MyHomepageState extends State<MyHomepage> {
  int _index = 0;

  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
      currentIndex: _index,
      onTap: (newIndex) {
        setState(() {
          _index = newIndex;
        });
      },
      // ... items ...
    );
  }
}

在这里,使用 setState() 和 StatefulWidget 的 State 类中的字段是完全自然的。应用的其他任何部分都不需要访问 _index。该变量只在 MyHomepage 小部件内部改变。而且,如果用户关闭并重新启动应用,你也不介意 _index 重置为零。

应用状态

#

不是暂时性的状态,你希望在应用的许多部分共享,并希望在用户会话之间保持,我们称之为应用状态(有时也称为共享状态)。

应用状态的例子

  • 用户偏好设置
  • 登录信息
  • 社交网络应用中的通知
  • 电子商务应用中的购物车
  • 新闻应用中文章的已读/未读状态

为了管理应用状态,你需要研究你的选择。你的选择取决于应用的复杂性和性质、团队之前的经验以及许多其他方面。请继续阅读。

没有明确的规则

#

需要明确的是,你*可以*使用 StatesetState() 来管理应用中的所有状态。事实上,Flutter 团队在许多简单的应用示例中(包括每次 flutter create 都会得到的起始应用)都是这样做的。

反之亦然。例如,你可能会决定——在你的特定应用的上下文中——底部导航栏中选中的选项卡*不是*暂时性状态。你可能需要从类外部改变它,在会话之间保持它,等等。在这种情况下,_index 变量就是应用状态。

没有一个明确的、普遍的规则来区分某个特定变量是暂时性状态还是应用状态。有时,你必须将一种状态重构为另一种。例如,你可能从一些明显的暂时性状态开始,但随着应用功能增长,它可能需要移动到应用状态。

因此,对下图要持保留态度。

A flow chart. Start with 'Data'. 'Who needs it?'. Three options: 'Most widgets', 'Some widgets' and 'Single widget'. The first two options both lead to 'App state'. The 'Single widget' option leads to 'Ephemeral state'.

当被问及 React 的 setState 与 Redux 的 store 时,Redux 的作者 Dan Abramov 回答道:

“经验法则是:选择最不麻烦的。”

总而言之,任何 Flutter 应用中都有两种概念上的状态类型。暂时性状态可以使用 StatesetState() 来实现,并且通常是单个小部件的局部状态。其余的是你的应用状态。这两种类型在任何 Flutter 应用中都有其位置,两者之间的划分取决于你自己的偏好和应用的复杂性。