Flutter Redux 状态管理详解
简介
Redux 是一个可预测的状态容器,它基于单向数据流的原则,通过 Action、Reducer 和 Store 来管理应用状态。Flutter Redux 是 Redux 在 Flutter 中的实现。
基本概念
State
dart
// 应用状态
class AppState {
final int counter;
final bool isLoading;
AppState({
this.counter = 0,
this.isLoading = false,
});
AppState copyWith({
int? counter,
bool? isLoading,
}) {
return AppState(
counter: counter ?? this.counter,
isLoading: isLoading ?? this.isLoading,
);
}
}
Action
dart
// 定义操作
class IncrementAction {}
class DecrementAction {}
class LoadDataAction {}
class LoadDataSuccessAction {}
class LoadDataFailureAction {
final String error;
LoadDataFailureAction(this.error);
}
Reducer
dart
// 状态更新逻辑
AppState appReducer(AppState state, dynamic action) {
if (action is IncrementAction) {
return state.copyWith(counter: state.counter + 1);
}
if (action is DecrementAction) {
return state.copyWith(counter: state.counter - 1);
}
if (action is LoadDataAction) {
return state.copyWith(isLoading: true);
}
if (action is LoadDataSuccessAction) {
return state.copyWith(isLoading: false);
}
return state;
}
基本用法
创建 Store
dart
void main() {
final store = Store<AppState>(
appReducer,
initialState: AppState(),
middleware: [thunkMiddleware],
);
runApp(
StoreProvider(
store: store,
child: MyApp(),
),
);
}
使用 Store
dart
// 读取状态
StoreConnector<AppState, int>(
converter: (store) => store.state.counter,
builder: (context, counter) {
return Text('Counter: $counter');
},
);
// 发送 Action
StoreProvider.of<AppState>(context).dispatch(IncrementAction());
完整示例
dart
// 用户状态
class UserState {
final User? user;
final bool isLoading;
final String? error;
UserState({
this.user,
this.isLoading = false,
this.error,
});
UserState copyWith({
User? user,
bool? isLoading,
String? error,
}) {
return UserState(
user: user ?? this.user,
isLoading: isLoading ?? this.isLoading,
error: error ?? this.error,
);
}
}
// 用户操作
class LoadUserAction {}
class LoadUserSuccessAction {
final User user;
LoadUserSuccessAction(this.user);
}
class LoadUserFailureAction {
final String error;
LoadUserFailureAction(this.error);
}
class UpdateUserAction {
final String name;
final int age;
UpdateUserAction({required this.name, required this.age});
}
// 用户 Reducer
UserState userReducer(UserState state, dynamic action) {
if (action is LoadUserAction) {
return state.copyWith(isLoading: true, error: null);
}
if (action is LoadUserSuccessAction) {
return state.copyWith(
user: action.user,
isLoading: false,
);
}
if (action is LoadUserFailureAction) {
return state.copyWith(
error: action.error,
isLoading: false,
);
}
if (action is UpdateUserAction) {
final updatedUser = state.user?.copyWith(
name: action.name,
age: action.age,
);
return state.copyWith(user: updatedUser);
}
return state;
}
// 异步 Action Creator
ThunkAction<UserState> loadUser() {
return (Store<UserState> store) async {
store.dispatch(LoadUserAction());
try {
final user = await UserRepository().fetchUser();
store.dispatch(LoadUserSuccessAction(user));
} catch (e) {
store.dispatch(LoadUserFailureAction(e.toString()));
}
};
}
// 页面组件
class UserPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Redux Demo')),
body: StoreConnector<UserState, UserViewModel>(
converter: (store) => UserViewModel(
user: store.state.user,
isLoading: store.state.isLoading,
error: store.state.error,
onLoadUser: () => store.dispatch(loadUser()),
onUpdateUser: (name, age) => store.dispatch(
UpdateUserAction(name: name, age: age),
),
),
builder: (context, vm) {
if (vm.isLoading) {
return Center(child: CircularProgressIndicator());
}
if (vm.error != null) {
return Center(child: Text('Error: ${vm.error}'));
}
if (vm.user == null) {
return Center(
child: ElevatedButton(
onPressed: vm.onLoadUser,
child: Text('Load User'),
),
);
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Name: ${vm.user!.name}',
style: TextStyle(fontSize: 24),
),
Text(
'Age: ${vm.user!.age}',
style: TextStyle(fontSize: 24),
),
ElevatedButton(
onPressed: () => vm.onUpdateUser('John Doe', 30),
child: Text('Update User'),
),
],
),
);
},
),
);
}
}
高级用法
中间件
dart
Middleware<AppState> loggingMiddleware = (
Store<AppState> store,
dynamic action,
NextDispatcher next,
) {
print('Action: $action');
next(action);
print('State: ${store.state}');
};
选择器
dart
class Selectors {
static User? getUser(UserState state) => state.user;
static bool isLoading(UserState state) => state.isLoading;
static String? getError(UserState state) => state.error;
}
组合 Reducer
dart
AppState appReducer(AppState state, dynamic action) {
return AppState(
user: userReducer(state.user, action),
settings: settingsReducer(state.settings, action),
);
}
最佳实践
- 使用不可变状态
- 保持 Action 简单明确
- 编写纯函数 Reducer
- 合理使用中间件
- 避免过度使用全局状态
注意事项
- 注意状态的粒度
- 避免在 Reducer 中进行副作用操作
- 合理组织 Action 和 Reducer
- 注意性能优化
- 处理好异步操作
总结
Redux 提供了一种可预测的状态管理方案,通过严格的单向数据流和不可变状态,可以构建出更易维护的应用程序。理解并掌握 Redux 的使用对于开发大型 Flutter 应用很有帮助。