短时 (ephemeral) 和应用 (app) 状态的区别

本文将介绍应用 (app) 状态、短时 (ephemeral) 状态,以及在一个 Flutter 应用中你可以如何应用这两种状态。

广义上来讲,一个应用的状态就是当这个应用运行时存在于内存中的所有内容。这包括了应用中用到的资源,所有 Flutter 框架中有关用户界面、动画状态、纹理、字体以及其他等等的变量。这个对于状态广义的定义是有效的,但是它对于构建一个应用来说并不是很有用。

首先,你不需要管理一些状态(例如纹理),框架本身会替你管理。所以对于状态的更有用的定义是 “当任何时候你需要重建你的用户界面时你所需要的数据”。其次,你需要自己 管理 的状态可以分为两种概念类型:短时 (ephemeral) 状态和应用 (app) 状态。

短时状态

#

短时状态(有时也称 用户界面 (UI) 状态 或者 局部状态)是你可以完全包含在一个独立 widget 中的状态。

这是一个有点儿模糊的定义,这里有几个例子。

  • 一个 PageView 组件中的当前页面

  • 一个复杂动画中当前进度

  • 一个 BottomNavigationBar 中当前被选中的 tab

widget 树中其他部分不需要访问这种状态。不需要去序列化这种状态,这种状态也不会以复杂的方式改变。

换句话说,不需要使用状态管理架构(例如 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() 和一个在有状态 widget 的 State 类中的变量是很自然的。你的 app 中的其他部分不需要访问 _index。这个变量只会在 MyHomepage widget 中改变。而且,如果用户关闭并重启这个 app,你不会介意 _index 重置回 0.

应用状态

#

如果你想在你的应用中的多个部分之间共享一个非短时的状态,并且在用户会话期间保留这个状态,我们称之为应用状态(有时也称共享状态)。

应用状态的一些例子:

  • 用户选项

  • 登录信息

  • 一个社交应用中的通知

  • 一个电商应用中的购物车

  • 一个新闻应用中的文章已读/未读状态

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

没有明确的规则

#

需要说明的是,你 可以 使用 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 应用中都存在两种概念类型的状态,短时状态经常被用于一个单独 widget 的本地状态,通常使用 StatesetState() 来实现。其他的是你的应用应用状态,在任何一个 Flutter 应用中这两种状态都有自己的位置。如何划分这两种状态取决于你的偏好以及应用的复杂度。