AsyncRedux前后方法Skill asyncredux-before-after

这个技能涉及在AsyncRedux库中使用`before()`和`after()`方法来增强Redux动作的生命周期管理。`before()`方法用于运行预处理检查如验证权限或显示加载指示器,而`after()`方法确保清理逻辑如隐藏指示器,并且总是执行,类似于finally块。适用于Flutter应用的状态管理,提高代码的可维护性和错误处理能力。关键词:AsyncRedux, ReduxAction, before方法, after方法, 生命周期管理, Flutter状态管理, 错误处理, 预处理, 后处理, 模态屏障, 动作混合。

移动开发 0 次安装 0 次浏览 更新于 3/19/2026

名称: asyncredux-before-after 描述: 实现动作生命周期方法 before()after()。涵盖运行预处理检查、显示/隐藏模态屏障、after() 中的清理逻辑,以及理解 after() 总是运行(类似于finally块)。

AsyncRedux 前后方法

动作生命周期概述

每个 ReduxAction 有三个按顺序执行的生命周期方法:

  1. before() - 首先运行,在reducer之前
  2. reduce() - 主要的reducer(必需)
  3. after() - 最后运行,总是执行

只有 reduce() 是必需的。before()after() 方法是用于管理副作用的可选钩子。

before() 方法

before() 方法在reducer运行之前执行。它可以是同步的或异步的。

同步 before()

class MyAction extends ReduxAction<AppState> {
  @override
  void before() {
    // 在reduce()之前同步运行
    print('动作开始');
  }

  @override
  AppState? reduce() {
    return state.copy(counter: state.counter + 1);
  }
}

异步 before()

class MyAction extends ReduxAction<AppState> {
  @override
  Future<void> before() async {
    // 在reduce()之前异步运行
    await validatePermissions();
  }

  @override
  Future<AppState?> reduce() async {
    final data = await fetchData();
    return state.copy(data: data);
  }
}

before() 中的预处理检查

如果 before() 抛出错误,reduce() 将不会运行。这使其非常适合验证:

class FetchUserData extends ReduxAction<AppState> {
  @override
  Future<void> before() async {
    if (!await hasInternetConnection()) {
      throw UserException('无网络连接');
    }
  }

  @override
  Future<AppState?> reduce() async {
    // 仅当before()完成无误时运行
    final user = await api.fetchUser();
    return state.copy(user: user);
  }
}

常见 before() 使用场景

  • 验证预处理条件(身份验证、权限)
  • 检查网络连接
  • 显示加载指示器或模态屏障
  • 记录动作开始以进行分析
  • 分发先决条件动作

after() 方法

after() 方法在reducer完成后执行。其关键特性是:它总是运行,即使 before()reduce() 抛出错误。这使其类似于 finally 块。

基本 after()

class MyAction extends ReduxAction<AppState> {
  @override
  AppState? reduce() {
    return state.copy(counter: state.counter + 1);
  }

  @override
  void after() {
    // 无论成功或失败,总是运行
    print('动作完成');
  }
}

确保清理

由于 after() 总是运行,它非常适合清理操作:

class SaveDocument extends ReduxAction<AppState> {
  @override
  Future<void> before() async {
    dispatch(ShowSavingIndicatorAction(true));
  }

  @override
  Future<AppState?> reduce() async {
    await api.saveDocument(state.document);
    return state.copy(lastSaved: DateTime.now());
  }

  @override
  void after() {
    // 即使保存失败也隐藏指示器
    dispatch(ShowSavingIndicatorAction(false));
  }
}

重要:永远不要从 after() 抛出错误

after() 方法不应抛出错误。从 after() 抛出的任何异常将异步出现在控制台中,且无法正常捕获:

// 错误 - 不要在after()中抛出
@override
void after() {
  if (someCondition) {
    throw Exception('这会导致问题');
  }
}

// 正确 - 优雅处理错误
@override
void after() {
  try {
    cleanup();
  } catch (e) {
    // 记录但不抛出
    logger.error('清理失败: $e');
  }
}

常见 after() 使用场景

  • 隐藏加载指示器或模态屏障
  • 关闭数据库连接或文件句柄
  • 释放临时资源
  • 记录动作完成以进行分析
  • 分发后续动作

模态屏障模式

一个常见模式是在异步操作期间显示模态屏障(阻塞覆盖层):

class MyAction extends ReduxAction<AppState> {
  @override
  Future<AppState?> reduce() async {
    String description = await read(Uri.http("numbersapi.com", "${state.counter}"));
    return state.copy(description: description);
  }

  @override
  void before() => dispatch(BarrierAction(true));

  @override
  void after() => dispatch(BarrierAction(false));
}

BarrierAction 将更新状态以显示/隐藏加载覆盖层:

class BarrierAction extends ReduxAction<AppState> {
  final bool show;
  BarrierAction(this.show);

  @override
  AppState reduce() => state.copy(showBarrier: show);
}

创建可重用混合

对于重复使用的模式,创建一个混合:

mixin Barrier on ReduxAction<AppState> {
  @override
  void before() {
    super.before();
    dispatch(BarrierAction(true));
  }

  @override
  void after() {
    dispatch(BarrierAction(false));
    super.after();
  }
}

然后应用于任何动作:

class FetchData extends ReduxAction<AppState> with Barrier {
  @override
  Future<AppState?> reduce() async {
    // 在此运行前自动显示屏障
    final data = await api.fetchData();
    return state.copy(data: data);
    // 即使出错,后自动隐藏屏障
  }
}

多个混合

您可以组合多个混合:

class ImportantAction extends ReduxAction<AppState> with Barrier, NonReentrant {
  @override
  Future<AppState?> reduce() async {
    // 既有模态屏障又防止重复分发
    return state;
  }
}

错误处理流程

理解错误如何与生命周期交互:

class MyAction extends ReduxAction<AppState> {
  @override
  Future<void> before() async {
    // 如果此抛出,reduce()被跳过,after()仍运行
  }

  @override
  Future<AppState?> reduce() async {
    // 如果此抛出,状态不变,after()仍运行
  }

  @override
  void after() {
    // 无论上述错误如何,总是运行
  }
}

检查完成情况

使用 ActionStatus 确定哪些方法完成:

var status = await dispatchAndWait(MyAction());

if (status.hasFinishedMethodBefore) {
  print('before() 完成');
}

if (status.hasFinishedMethodReduce) {
  print('reduce() 完成');
}

if (status.hasFinishedMethodAfter) {
  print('after() 完成');
}

if (status.isCompletedOk) {
  print('before() 和 reduce() 均完成无误');
}

if (status.isCompletedFailed) {
  print('错误: ${status.originalError}');
}

与 abortDispatch() 的关系

如果 abortDispatch() 返回 true,则没有生命周期方法运行:

class MyAction extends ReduxAction<AppState> {
  @override
  bool abortDispatch() => state.user == null;

  @override
  void before() {
    // 如果abortDispatch()返回true,则跳过
  }

  @override
  AppState? reduce() {
    // 如果abortDispatch()返回true,则跳过
  }

  @override
  void after() {
    // 如果abortDispatch()返回true,则跳过
  }
}

完整示例

class SubmitForm extends ReduxAction<AppState> {
  final String formData;
  SubmitForm(this.formData);

  @override
  Future<void> before() async {
    // 验证预处理条件
    if (state.user == null) {
      throw UserException('请先登录');
    }

    if (!await checkInternetConnection()) {
      throw UserException('无网络连接');
    }

    // 显示加载状态
    dispatch(SetSubmittingAction(true));
  }

  @override
  Future<AppState?> reduce() async {
    final result = await api.submitForm(formData);
    return state.copy(
      lastSubmission: result,
      submissionCount: state.submissionCount + 1,
    );
  }

  @override
  void after() {
    // 即使出错,总是隐藏加载状态
    dispatch(SetSubmittingAction(false));

    // 记录完成
    analytics.log('form_submitted');
  }
}

内置混合使用 before() 和 after()

几个AsyncRedux混合在内部使用这些方法:

混合 使用 before() 使用 after() 目的
CheckInternet 验证连接性,离线时显示对话框
AbortWhenNoInternet 离线时静默中止
Throttle 限制执行频率
NonReentrant 防止重复分发
Retry 失败时重试
Debounce 等待输入暂停(使用 wrapReduce

使用这些混合时,请注意它们可能已覆盖 before()after()。如果需要组合行为,请调用 super.before()super.after()

参考

文档URL: