Flutter异步状态管理插件redux_future_middleware的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter 异步状态管理插件 redux_future_middleware 的使用

简介

Redux Future Middleware 是一个用于处理 Dart Futures 的 Redux 中间件包。通过创建一个 FutureAction,该中间件可以拦截并处理异步操作。

使用步骤

  1. 创建 AppState AppState 类用于存储应用程序的当前状态。

    class AppState {
      String value;
      String loadingValue;
    }
    
  2. 定义 Action 定义一个独特的 Action 来标识每个 FutureAction

    class ExampleAction {}
    
  3. 创建 Reducer 创建一个 Reducer 来处理未来的动作。

    AppState exampleReducer(AppState prevState, dynamic action) {
      if (action is FuturePendingAction<ExampleAction>) {
        return prevState..loadingValue = 'Fetching';
      } else if (action is FutureSucceededAction<ExampleAction, String>) {
        return prevState..value = action.payload..loadingValue = 'Done';
      } else if (action is FutureFailedAction<ExampleAction>) {
        return prevState..loadingValue = 'Failed';
      }
    
      return prevState;
    }
    
  4. 创建 Store 创建一个包含 futureMiddleware 的 Store。它将拦截所有被分发的 FutureAction

    final store = Store<AppState>(
      exampleReducer,
      middleware: [futureMiddleware],
    );
    
  5. 分发 FutureAction 分发一个 FutureAction 进行拦截。

    store.dispatch(FutureAction<ExampleAction, String>(
      future: Future.value('Hi'),
    ));
    

简化 Reducer 逻辑

该库现在附带了一个 FutureReducer 工具,可以帮助减少在创建处理 FuturePendingActionFutureFailedAction 的 Reducer 时所需的冗余逻辑。

内置默认值

使用内置默认值,上述示例可以简化为:

class AppState extends BaseState<AppState> {
  String value;
}

FutureReducer<AppState, ExampleAction, String> exampleReducer =
  FutureReducer<AppState, ExampleAction, String>(
    successReducer: successReducer,
);

其中 BaseState 类扩展了 FutureState 类,并实现了一些默认行为。

class BaseState extends FutureState<BaseState> {
  String loadingValue;

  [@override](/user/override)
  BaseState updateOnFailed(FutureFailedAction action) => this
    ..loadingValue = "Failed";

  [@override](/user/override)
  BaseState updateOnPending(FuturePendingAction action) => this
    ..loadingValue = "Fetching";
}
自定义默认值

如果您不想使用 FutureState 和内置默认值,可以设置自己的默认 pendingReducerfailedReducer

FutureReducer<AppState, ExampleAction, String> exampleReducer =
  FutureReducer<AppState, ExampleAction, String>(
    successReducer: successReducer,
    pendingReducer: pendingReducer,
    failedReducer: failedReducer,
);

完整示例

以下是一个完整的示例代码,展示了如何使用 redux_future_middleware

import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
import 'package:redux_future_middleware/redux_future_middleware.dart';

// 定义 AppState
class AppState {
  String value;
  String loadingValue;

  AppState(this.value, this.loadingValue);

  AppState copyWith({String? value, String? loadingValue}) {
    return AppState(value ?? this.value, loadingValue ?? this.loadingValue);
  }
}

// 定义 Action
class ExampleAction {}

// 定义 Reducer
AppState exampleReducer(AppState prevState, dynamic action) {
  if (action is FuturePendingAction<ExampleAction>) {
    return prevState.copyWith(loadingValue: 'Fetching');
  } else if (action is FutureSucceededAction<ExampleAction, String>) {
    return prevState.copyWith(value: action.payload, loadingValue: 'Done');
  } else if (action is FutureFailedAction<ExampleAction>) {
    return prevState.copyWith(loadingValue: 'Failed');
  }

  return prevState;
}

void main() {
  final store = Store<AppState>(
    exampleReducer,
    initialState: AppState('', ''),
    middleware: [futureMiddleware],
  );

  runApp(MyApp(store: store));
}

class MyApp extends StatelessWidget {
  final Store<AppState> store;

  MyApp({required this.store});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return StoreProvider<AppState>(
      store: store,
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(title: 'Flutter Demo Home Page'),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final String? title;

  MyHomePage({this.title});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return StoreConnector<AppState, AppState>(
      converter: (store) => store.state,
      builder: (context, state) {
        return Scaffold(
          appBar: AppBar(
            title: Text(title!),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(
                  'Loading Value:',
                ),
                Text(
                  state.loadingValue,
                  style: Theme.of(context).textTheme.headline4,
                ),
                Text(
                  'Value:',
                ),
                Text(
                  state.value,
                  style: Theme.of(context).textTheme.headline4,
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              store.dispatch(FutureAction<ExampleAction, String>(
                future: Future.value('Hello World'),
              ));
            },
            tooltip: 'Fetch Data',
            child: Icon(Icons.refresh),
          ),
        );
      },
    );
  }
}

更多关于Flutter异步状态管理插件redux_future_middleware的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter异步状态管理插件redux_future_middleware的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用redux_future_middleware进行异步状态管理的代码示例。redux_future_middleware 是一个中间件,它允许你将 Future 操作与 Redux 状态管理结合起来,从而更容易地处理异步任务的状态(如加载中、成功、失败)。

首先,确保你的pubspec.yaml文件中包含以下依赖项:

dependencies:
  flutter:
    sdk: flutter
  flutter_redux: ^0.6.0  # 或者最新版本
  redux: ^4.0.0  # 或者最新版本
  redux_future_middleware: ^0.4.0  # 或者最新版本

然后,运行flutter pub get来安装这些依赖。

接下来,我们创建一个简单的Flutter应用,演示如何使用redux_future_middleware

1. 创建Action和Action Creator

import 'package:redux/redux.dart';
import 'package:redux_future_middleware/redux_future_middleware.dart';

// 定义Action类型
enum AppActionTypes { loadDataRequest, loadDataSuccess, loadDataFailure }

// 定义Action
class LoadDataRequestAction {}
class LoadDataSuccessAction {
  final List<String> data;
  LoadDataSuccessAction(this.data);
}
class LoadDataFailureAction {
  final String error;
  LoadDataFailureAction(this.error);
}

// Action Creator
Future<dynamic> loadDataRequest() async {
  return FutureActionCreator(
    AppActionTypes.loadDataRequest,
    () async {
      // 模拟一个异步操作,例如从网络获取数据
      await Future.delayed(Duration(seconds: 2));
      try {
        final data = List<String>.generate(10, (i) => "Item $i");
        return LoadDataSuccessAction(data);
      } catch (e) {
        return LoadDataFailureAction(e.toString());
      }
    },
  )();
}

2. 创建Reducer

import 'package:redux/redux.dart';
import 'package:redux_future_middleware/redux_future_middleware.dart';
import 'package:meta/meta.dart';

// 定义AppState
class AppState {
  final List<String> data;
  final FutureStatus<Null> loadDataStatus;

  AppState({
    @required this.data,
    @required this.loadDataStatus,
  });

  factory AppState.initial() {
    return AppState(
      data: [],
      loadDataStatus: FutureStatus.pending(),
    );
  }

  AppState copyWith({
    List<String> data,
    FutureStatus<Null> loadDataStatus,
  }) {
    return AppState(
      data: data ?? this.data,
      loadDataStatus: loadDataStatus ?? this.loadDataStatus,
    );
  }
}

// 创建Reducer
Reducer<AppState> appReducer = combineReducers<AppState>([
  TypedReducer<AppState, FutureAction<Null>>(_handleLoadData, AppActionTypes.loadDataRequest),
  TypedReducer<AppState, LoadDataSuccessAction>(_handleLoadDataSuccess),
  TypedReducer<AppState, LoadDataFailureAction>(_handleLoadDataFailure),
]);

AppState _handleLoadData(AppState state, action) {
  return state.copyWith(loadDataStatus: action.status);
}

AppState _handleLoadDataSuccess(AppState state, LoadDataSuccessAction action) {
  return state.copyWith(
    data: action.data,
    loadDataStatus: FutureStatus.completed(),
  );
}

AppState _handleLoadDataFailure(AppState state, LoadDataFailureAction action) {
  return state.copyWith(
    loadDataStatus: FutureStatus.rejected(action.error),
  );
}

3. 设置Store

import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
import 'package:redux_future_middleware/redux_future_middleware.dart';

void main() {
  final store = Store<AppState>(
    appReducer,
    initialState: AppState.initial(),
    middleware: [createFutureMiddleware()],
  );

  runApp(StoreProvider<AppState>(
    store: store,
    child: MyApp(),
  ));
}

4. 在UI中使用Store

import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
import 'package:redux_future_middleware/redux_future_middleware.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Redux Future Middleware Demo')),
        body: Center(
          child: StoreConnector<AppState, _ViewModel>(
            converter: (store) => _ViewModel.fromStore(store),
            builder: (_, vm) {
              return Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  if (vm.isLoading) CircularProgressIndicator(),
                  if (vm.hasError) Text('Error: ${vm.error}'),
                  if (vm.data.isNotEmpty) Text('Data: ${vm.data.join(", ")}'),
                  ElevatedButton(
                    onPressed: vm.loadData,
                    child: Text('Load Data'),
                  ),
                ],
              );
            },
          ),
        ),
      ),
    );
  }
}

class _ViewModel {
  final List<String> data;
  final bool isLoading;
  final String error;
  final Function loadData;

  _ViewModel({
    this.data,
    this.isLoading,
    this.error,
    this.loadData,
  });

  factory _ViewModel.fromStore(Store<AppState> store) {
    return _ViewModel(
      data: store.state.data,
      isLoading: store.state.loadDataStatus.isPending,
      error: store.state.loadDataStatus.maybeMap(
        rejected: (e) => e.error,
        orElse: () => null,
      ),
      loadData: () => store.dispatch(loadDataRequest()),
    );
  }
}

这个示例演示了如何使用redux_future_middleware来处理异步操作的状态管理。我们通过FutureActionCreator来创建一个异步操作,并使用FutureStatus来跟踪这个操作的状态。Reducer根据操作的状态来更新应用的状态,而UI则根据最新的状态来渲染相应的组件。

回到顶部