Skip to content

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
中小型 AppRiverpod 或 Provider
大型 / 团队协作Bloc/Cubit 或 Riverpod
追求效率GetX(承担其架构债务)

四、给新手的建议

  1. 先掌握 setState 和 Provider,理解"状态从哪来、到哪去"
  2. 新项目直接上 Riverpod,目前社区最活跃、设计最现代
  3. 不要在一个项目混用多种方案,保持一致性比"用最好的"更重要
  4. 状态尽量提到必要的最低层级,避免一切都丢到全局

最后更新: