Flutter 状态管理入门速记

目标

用最小心智负担理解 setState、Provider、Riverpod 的区别

1. 从 setState 开始

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class CounterPage extends StatefulWidget {
const CounterPage({super.key});

@override
State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
int count = 0;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(child: Text('count: $count')),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => count++),
child: const Icon(Icons.add),
),
);
}
}

适合:

  • 页面内部的小状态
  • 生命周期和页面强绑定

2. Provider(中小项目够用)

1
2
3
4
5
6
7
8
class CounterModel extends ChangeNotifier {
int count = 0;

void inc() {
count++;
notifyListeners();
}
}
1
2
3
4
ChangeNotifierProvider(
create: (_) => CounterModel(),
child: const App(),
)
1
2
3
Consumer<CounterModel>(
builder: (_, model, __) => Text('count: ${model.count}'),
)

适合:

  • 有跨组件共享状态需求
  • 团队成员都熟悉 ChangeNotifier 风格

3. Riverpod(可测试性更好)

1
final counterProvider = StateProvider<int>((ref) => 0);
1
2
3
4
5
6
7
8
9
class CounterText extends ConsumerWidget {
const CounterText({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Text('count: $count');
}
}
1
ref.read(counterProvider.notifier).state++;
建议

新项目如果没有历史包袱,可以直接从 Riverpod 起步。

4. 选型建议

快速决策

  • 单页简单状态:setState
  • 中小项目共享状态:Provider
  • 追求可测试和可维护:Riverpod

5. 常见问题

为什么页面频繁重建?

通常是 watch 了过大的状态,或 widget 拆分不够细。

优化方式:

  1. 状态切片
  2. 拆分小组件
  3. 使用 selector(Provider)或精细 watch(Riverpod)