Flutter 状态管理详解
状态管理是 Flutter 开发中的核心话题。简单说,状态就是 UI 在某一时刻需要展示的数据,状态管理就是决定"数据放在哪里、谁能改、改了之后怎么通知 UI 刷新"。
一、状态的分类
| 类型 | 说明 | 示例 |
|---|---|---|
| 局部状态(Ephemeral) | 单个 Widget 内部使用,不需要共享 | TextField 的输入、动画进度 |
| 应用状态(App State) | 跨多个页面/Widget 共享 | 用户登录信息、购物车、主题 |
经验法则:能用局部状态就别用全局,避免过度工程化。
二、主流方案对比
1. setState(官方原生)
最基础的方式,适合 局部状态。
dart
class CounterPage extends StatefulWidget {
@override
State<CounterPage> createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int _count = 0;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => setState(() => _count++),
child: Text('$_count'),
);
}
}- 优点:简单直接
- 缺点:跨组件共享困难,容易引发整个 widget tree 重建
2. InheritedWidget(底层基石)
Flutter 的"祖宗级"方案,几乎所有第三方库都基于它。通过 context.dependOnInheritedWidgetOfExactType() 让子 Widget 访问祖先数据。
实际项目中很少手写,但理解它能帮你看懂其他库的源码。
3. Provider(官方推荐入门)
基于 InheritedWidget 的封装,Google 官方曾力推。
dart
// 1. 定义 Model
class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
// 2. 注入
ChangeNotifierProvider(
create: (_) => Counter(),
child: MyApp(),
)
// 3. 使用
Consumer<Counter>(
builder: (_, counter, __) => Text('${counter.count}'),
)
// 或
context.watch<Counter>().count; // 监听变化
context.read<Counter>().increment(); // 只触发动作适合:中小型项目,学习曲线平缓
4. Riverpod(Provider 作者新作,目前最推荐)
修复了 Provider 的几个痛点:编译期安全、不依赖 BuildContext、更好的测试性。
dart
// 定义
final counterProvider = StateNotifierProvider<Counter, int>((ref) => Counter());
class Counter extends StateNotifier<int> {
Counter() : super(0);
void increment() => state++;
}
// 使用(Widget 继承 ConsumerWidget)
class MyWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Text('$count');
}
}新版还有 代码生成(@riverpod 注解),写起来更简洁。
5. Bloc / Cubit(企业级首选)
基于事件流(Stream),严格遵守单向数据流。Cubit 是 Bloc 的简化版。
dart
// Cubit 版本
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
}
// 使用
BlocBuilder<CounterCubit, int>(
builder: (_, count) => Text('$count'),
)适合:大型团队、复杂业务、强测试需求
6. GetX(国内/中小项目流行)
把状态管理、路由、依赖注入打包,API 极简。
dart
class CounterController extends GetxController {
var count = 0.obs;
void increment() => count++;
}
// 使用
final c = Get.put(CounterController());
Obx(() => Text('${c.count}'));- 优点:快、写得少
- 争议:过度耦合、违反一些 Flutter 设计哲学,大型项目慎用
7. 其他
- MobX:响应式,基于注解,代码生成
- Redux:从 React 移植,模板代码多,新项目少用
- signals_flutter:借鉴 Preact/Solid 的细粒度响应式,新兴方案
三、如何选择
| 项目规模 | 推荐方案 |
|---|---|
| demo / 学习 | setState + Provider |
| 中小型 App | Riverpod 或 Provider |
| 大型 / 团队协作 | Bloc/Cubit 或 Riverpod |
| 追求效率 | GetX(承担其架构债务) |
四、给新手的建议
- 先掌握 setState 和 Provider,理解"状态从哪来、到哪去"
- 新项目直接上 Riverpod,目前社区最活跃、设计最现代
- 不要在一个项目混用多种方案,保持一致性比"用最好的"更重要
- 状态尽量提到必要的最低层级,避免一切都丢到全局