第6章:状态管理
在 Flutter 中,状态(State) 决定了 Widget 的显示内容。所谓“状态管理”,就是在 UI 和数据之间建立可靠的更新机制,让数据变化时 UI 自动更新。
一、什么是状态?
Flutter 中状态大致分为两种:
| 类型 | 示例 | 生命周期 |
|---|---|---|
| 临时状态 | 输入框内容、选中项等 | 短暂存在 |
| 应用级状态 | 登录信息、主题设置、购物车等 | 长时间存在 |
二、使用 setState 进行局部状态管理(最基础)
适用于小范围状态更新,如按钮点击、单个组件变更。
示例:
class CounterPage extends StatefulWidget {
@override
_CounterPageState createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int count = 0;
void _increment() {
setState(() {
count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $count'),
ElevatedButton(onPressed: _increment, child: Text('Add')),
],
);
}
}
⚠️ 注意事项:
- 每次
setState()都会触发build()重建整个 Widget 树 - 不适用于跨组件或大范围共享状态
三、使用 Provider 进行全局或多组件状态共享
Provider 是 Google 推荐的轻量状态管理方案,适合实际项目中使用。
1. 添加依赖
dependencies:
provider: ^6.0.0
2. 创建状态类
class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners(); // 通知监听者刷新 UI
}
}
3. 注册状态提供者(根节点)
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => Counter(),
child: MyApp(),
),
);
}
4. 在 Widget 中使用状态
Consumer<Counter>(
builder: (context, counter, child) {
return Text('Count: ${counter.count}');
},
)
ElevatedButton(
onPressed: () => context.read<Counter>().increment(),
child: Text('Add'),
)
四、其他常见状态管理方案(了解即可)
| 方案 | 特点 |
|---|---|
| Riverpod | Provider 升级版,类型安全、全局共享 |
| Bloc | 适合中大型项目,状态集中、事件驱动 |
| GetX | 上手简单,语法简洁,适合快速开发 |
| Redux | 借鉴 React Redux,逻辑清晰但冗长复杂 |
五、常见问题解析
❗ 问题 1:setState 不生效
原因:
- 使用
setState的组件是StatelessWidget setState()调用后数据未真正变化- 被覆盖的变量是局部变量而非状态字段
示例:
// 错误
onPressed: () {
int count = 0;
setState(() {
count++; // 实际是局部变量
});
}
❗ 问题 2:Provider 更新后 UI 不刷新
检查:
- 是否调用了
notifyListeners()? - UI 中是否用
Consumer或context.watch<T>()? - 是否多层嵌套导致无法监听?
示例解决方案:
Consumer<Counter>(...) ✅ 推荐使用
context.watch<Counter>().count ✅ 实时更新
❗ 问题 3:多个页面共享状态失败
- 根节点未正确注册
Provider - 页面跳转使用了
Navigator.push,但未继承 Provider 上下文 - 可以使用
MultiProvider注册多个状态对象