公告

👇欢迎大家关注公众号&私信交流👇

Skip to content

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),
  );
}

最佳实践

  1. 使用不可变状态
  2. 保持 Action 简单明确
  3. 编写纯函数 Reducer
  4. 合理使用中间件
  5. 避免过度使用全局状态

注意事项

  1. 注意状态的粒度
  2. 避免在 Reducer 中进行副作用操作
  3. 合理组织 Action 和 Reducer
  4. 注意性能优化
  5. 处理好异步操作

总结

Redux 提供了一种可预测的状态管理方案,通过严格的单向数据流和不可变状态,可以构建出更易维护的应用程序。理解并掌握 Redux 的使用对于开发大型 Flutter 应用很有帮助。