区分瞬时状态和应用状态
本文档介绍了应用状态、瞬时状态以及如何在 Flutter 应用中管理它们。
从最广义上讲,应用的状态是指应用运行时内存中存在的一切。这包括应用的资产、Flutter 框架维护的所有UI相关变量、动画状态、纹理、字体等等。虽然这种最广义的状态定义是有效的,但对于架构应用来说并不十分有用。
首先,有些状态(如纹理)你甚至无需管理。框架会为你处理这些。因此,一个更有用的状态定义是“随时重建UI所需的所有数据”。其次,你确实需要自己管理的状态可以分为两种概念类型:瞬时状态和应用状态。
瞬时状态
#瞬时状态(有时也称为UI状态或局部状态)是你可以整齐地包含在单个widget中的状态。
这是,刻意模糊的定义,因此这里有一些示例。
- 在
PageView
中的当前页面 - 复杂动画的当前进度
BottomNavigationBar
中当前选中的标签页
widget 树的其他部分很少需要访问这种状态。没有必要将其序列化,它也不会以复杂的方式改变。
换句话说,没有必要在这种状态上使用状态管理技术(如 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
widget 内部改变。而且,如果用户关闭并重新启动应用,你也不会介意 _index
重置为零。
应用状态
#非瞬时状态、需要在应用的许多部分共享、并且希望在用户会话之间保留的状态,我们称之为应用状态(有时也称为共享状态)。
应用状态的示例
- 用户偏好设置
- 登录信息
- 社交应用中的通知
- 电商应用中的购物车
- 新闻应用中文章的已读/未读状态
为了管理应用状态,你需要研究可用的选项。你的选择取决于应用的复杂性和性质、团队的经验以及许多其他方面。继续阅读。
没有明确的规则
#需要明确的是,你可以使用 State
和 setState()
来管理应用中的所有状态。事实上,Flutter 团队在许多简单的应用示例中都是这样做的(包括每次 flutter create
时得到的入门应用)。
反之亦然。例如,你可能会决定——在你的特定应用场景中——底部导航栏中选定的标签页不是瞬时状态。你可能需要从类外部更改它,在会话之间保持它等等。在这种情况下,_index
变量就是应用状态。
没有明确、通用的规则来区分某个变量是瞬时状态还是应用状态。有时,你可能需要将一种状态重构为另一种。例如,你可能会从一些明显的瞬时状态开始,但随着应用功能的增长,它可能需要被移动到应用状态。
因此,对以下图表请持保留态度

当被问及 React 的 setState 与 Redux 的 store 之间的区别时,Redux 的作者 Dan Abramov 回答道:
“经验法则是:做任何不那么别扭的事情。”
总而言之,任何 Flutter 应用中都有两种概念上的状态类型。瞬时状态可以使用 State
和 setState()
实现,并且通常局限于单个 widget。其余的是你的应用状态。这两种状态类型在任何 Flutter 应用中都有其位置,它们之间的划分取决于你自己的偏好和应用的复杂性。