前言
如果你写 Flutter 写到一定阶段,迟早会遇到一个问题:
项目一开始很简单,用
setState就够了 过一阵子开始加 Provider 再后来又有人提 Riverpod / Bloc 最后大家都在问:我们到底该用哪个?
如果你有前端或者 RN 经验,这一幕其实一点都不陌生。
Redux、MobX、Zustand、Recoil…… 前端早就经历过一次完整的'状态管理百家争鸣'。
那问题来了:
为什么 Flutter 这么快就走上了和前端一模一样的路?
状态为什么会'爆炸'?不是 Flutter 的锅
先说一个很多人不太愿意承认的事实:
状态复杂化,几乎是所有中大型应用的必经之路。
状态从什么时候开始失控?
你回忆一下项目的演进路径,通常是这样的:
- 一开始:
页面里几个变量,
setState很香 - 业务变复杂: 表单、列表、筛选条件、分页状态开始增多
- 再后来: 登录态、用户信息、权限、配置、缓存
- 最后: 多页面共享状态 + 异步 + 回退恢复
这时候你会发现一个很现实的问题:
状态已经不再属于'某一个 Widget / 页面'了。
而一旦状态开始跨页面、跨模块存在,单纯的 setState 就一定会崩。
Flutter 和前端,状态模型几乎是同构的
这也是为什么 Flutter 会自然长出一堆状态管理方案。
因为 Flutter 和 React 本质上解决的是同一个问题:
UI = f(State)
状态一变,就要重新描述 UI。
对比一下两边的状态形态
前端 / RN
- 组件本地状态
- 页面级状态
- 全局状态(用户、配置、权限)
Flutter
- Widget 内部 State
- 页面级 State(ViewModel / Controller)
- 全局 State(Provider / Riverpod)
你会发现,层级是一模一样的,只是名字不同。
一个 Flutter 中最典型的'状态开始失控'的例子
先看一个非常常见的写法。
初期写法:状态直接写在页面里
class UserPage extends StatefulWidget {
@override
State<UserPage> createState() => _UserPageState();
}
class _UserPageState extends State<UserPage> {
bool loading = false;
String userName = '';
Future<void> loadUser() async {
setState(() {
loading = true;
});
await Future.delayed(Duration(seconds: 1));
setState(() {
userName = 'Tom';
loading = false;
});
}
@override
void initState() {
super.initState();
loadUser();
}
@override
Widget build(BuildContext context) {
return loading
? CircularProgressIndicator()
: Text('Hello $userName');
}
}


