以下是 Redux 在 Flutter 中的完整实现示例,包含详细的代码注释和状态管理流程:
Redux 核心概念实现
1. 添加依赖
# pubspec.yaml
dependencies:
flutter_redux: ^0.8.2
redux: ^5.0.0
# 可选:处理异步 Action
redux_thunk: ^0.4.0
2. 定义 State(状态)
// 定义全局状态类
class AppState {
final int count;
final String message;
AppState({required this.count, required this.message});
// 创建初始状态
factory AppState.initial() {
return AppState(count: 0, message: 'Redux Demo');
}
// 生成新状态(不可变原则)
AppState copyWith({int? count, String? message}) {
return AppState(
count: count ?? this.count,
message: message ?? this.message,
);
}
}
3. 定义 Action(动作)
// 定义所有可能的 Action 类型
abstract class CounterAction {}
// 增加计数
class IncrementAction extends CounterAction {}
// 减少计数
class DecrementAction extends CounterAction {}
// 带参数的自定义 Action
class UpdateMessageAction extends CounterAction {
final String newMessage;
UpdateMessageAction(this.newMessage);
}
4. 定义 Reducer(状态处理器)
// 创建 Reducer 处理 Action
AppState appReducer(AppState state, dynamic action) {
if (action is IncrementAction) {
return state.copyWith(count: state.count + 1);
} else if (action is DecrementAction) {
return state.copyWith(count: state.count - 1);
} else if (action is UpdateMessageAction) {
return state.copyWith(message: action.newMessage);
}
return state;
}
5. 创建 Store 并注入应用
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
void main() {
// 创建全局 Store
final store = Store<AppState>(
appReducer,
initialState: AppState.initial(),
middleware: [
// 可添加中间件(如日志、异步处理)
loggingMiddleware,
],
);
runApp(MyApp(store: store));
}
// 中间件示例:打印 Action 日志
void loggingMiddleware<State>(
Store<State> store,
dynamic action,
NextDispatcher next,
) {
print('Action: $action');
next(action);
}
class MyApp extends StatelessWidget {
final Store<AppState> store;
MyApp({required this.store});
@override
Widget build(BuildContext context) {
return StoreProvider<AppState>(
store: store,
child: MaterialApp(
home: CounterPage(),
),
);
}
}
6. UI 组件与 Store 交互
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Redux Counter')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 显示消息
StoreConnector<AppState, String>(
converter: (store) => store.state.message,
builder: (context, message) => Text(message),
),
// 显示计数
StoreConnector<AppState, int>(
converter: (store) => store.state.count,
builder: (context, count) => Text('Count: $count'),
),
// 操作按钮
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(Icons.add),
onPressed: () => StoreProvider.of<AppState>(context)
.dispatch(IncrementAction()),
),
IconButton(
icon: Icon(Icons.remove),
onPressed: () => StoreProvider.of<AppState>(context)
.dispatch(DecrementAction()),
),
],
),
// 修改消息
TextField(
onSubmitted: (text) => StoreProvider.of<AppState>(context)
.dispatch(UpdateMessageAction(text)),
decoration: InputDecoration(hintText: '输入新消息'),
)
],
),
),
);
}
}
Redux 数据流图示
┌───────────┐ ┌─────────┐ ┌──────────┐
│ UI │─────▶ │ Action │─────▶ │ Reducer │
└───────────┘ └─────────┘ └──────────┘
▲ │ │
│ └───────┐ │
│ ▼ ▼
│ ┌───────────┐
└────────────────────────│ Store │
└───────────┘
Redux 优缺点分析
| 优点 | 缺点 |
|---|---|
| 严格单向数据流,状态变化可预测 | 代码冗余,需要定义大量 Action/Reducer |
| 全局状态集中管理,易于调试追溯 | 学习曲线陡峭,概念较多 |
| 支持中间件(日志、异步、持久化) | 小型项目中使用可能过于复杂 |
| 适合大型团队协作开发 | 需要手动处理不可变状态 |
何时选择 Redux?
- 需要严格审计状态变化历史(如金融类应用)
- 大型团队需要统一的状态管理规范
- 应用存在复杂的跨组件状态交互
- 需要中间件处理异步、日志、缓存等
如果需要处理 异步操作(如网络请求),可以结合 redux_thunk:
// 定义异步 Action
class FetchDataAction extends CounterAction {
final String url;
FetchDataAction(this.url);
}
// 在 Reducer 中处理
AppState appReducer(AppState state, dynamic action) {
// ...其他处理
if (action is FetchDataAction) {
// 触发网络请求(需使用 redux_thunk)
return state.copyWith(message: 'Loading...');
}
}
// 使用 Thunk 中间件
final store = Store<AppState>(
appReducer,
initialState: AppState.initial(),
middleware: [thunkMiddleware],
);
// 发起异步 Action
void fetchData(BuildContext context) {
StoreProvider.of<AppState>(context).dispatch(
(Store<AppState> store) async {
final response = await http.get(Uri.parse('https://api.example.com/data'));
store.dispatch(UpdateMessageAction(response.body));
},
);
}