Redux 在 Flutter 中使用

236 阅读2分钟

以下是 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?

  1. 需要严格审计状态变化历史(如金融类应用)
  2. 大型团队需要统一的状态管理规范
  3. 应用存在复杂的跨组件状态交互
  4. 需要中间件处理异步、日志、缓存等

如果需要处理 异步操作(如网络请求),可以结合 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));
    },
  );
}