区分短暂状态和应用状态

本文档介绍了应用状态、短暂状态以及如何在 Flutter 应用中管理每种状态。

从最广义的角度来看,应用的状态是在应用运行时存在于内存中的所有内容。这包括应用的资产、Flutter 框架保留的所有关于 UI 的变量、动画状态、纹理、字体等。虽然这种最广义的状态定义是有效的,但对于设计应用的架构来说并不是很有用。

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

短暂状态

短暂状态(有时称为UI 状态本地状态)是你可以在单个小组件中整齐包含的状态。

这是一个故意模糊的定义,这里有一些示例。

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

小组件树的其他部分很少需要访问这种状态。没有必要对其进行序列化,并且它不会以复杂的方式更改。

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

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

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 应用中都有其位置,并且两者之间的分割取决于您自己的偏好和应用的复杂性。