跳到主内容

区分临时状态 (Ephemeral state) 和应用状态 (App state)

如何区分临时状态和应用状态。

本文介绍了什么是应用状态、临时状态,以及如何在 Flutter 应用中管理它们。

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

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

临时状态

#

临时状态(有时称为 UI 状态局部状态)是指你可以整齐地包含在单个 widget 中的状态。

这是一个有意为之的模糊定义,因此这里列举几个示例。

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

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() 和 StatefulWidget 的 State 类中的字段是非常自然的。应用的其余部分不需要访问 _index。该变量仅在 MyHomepage widget 内部发生变化。而且,如果用户关闭并重新启动应用,你也不会在意 _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() 实现,通常局限于单个 widget。其余的则是你的应用状态。这两种类型在任何 Flutter 应用中都有其一席之地,两者之间的划分取决于你自己的偏好和应用的复杂程度。