异步Redux等待条件Skill asyncredux-wait-condition

这是一个用于Dart/Flutter中Redux的异步等待方法,允许在actions中暂停执行直到应用状态满足特定条件。适用于等待价格阈值、协调动作间的依赖和实现条件工作流。关键词:Redux, Dart, Flutter, 异步编程, 状态管理, 条件执行, 移动开发。

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

name: asyncredux-wait-condition description: 在actions中使用waitCondition()来暂停执行,直到状态满足条件。涵盖等待价格阈值、协调actions之间的依赖以及实现条件工作流。

使用waitCondition()等待状态条件

waitCondition()方法暂停执行,直到应用状态满足特定条件。它在StoreReduxAction类中都可用。

方法签名

Future<ReduxAction<St>?> waitCondition(
  bool Function(St) condition, {
  bool completeImmediately = true,
  int? timeoutMillis,
});

参数:

  • condition: 一个函数,接收当前状态并返回true当条件满足时
  • completeImmediately: 如果true(默认),当条件已经满足时立即完成。如果false,等待状态变化以满足条件
  • timeoutMillis: 最大等待时间(默认10分钟)。设置为-1禁用超时

返回: 触发条件变为true的action,或null如果条件已经满足。

基本用法在Action内部

当你的action需要等待先决状态时使用waitCondition()

class AddAppointmentAction extends ReduxAction<AppState> {
  final String title;
  final DateTime date;

  AddAppointmentAction({required this.title, required this.date});

  @override
  Future<AppState?> reduce() async {
    // 确保日历存在在添加预约之前
    if (state.calendar == null) {
      dispatch(CreateCalendarAction());

      // 等待直到日历可用
      await waitCondition((state) => state.calendar != null);
    }

    // 现在安全添加预约
    return state.copy(
      calendar: state.calendar!.addAppointment(
        Appointment(title: title, date: date),
      ),
    );
  }
}

等待值阈值

等待数字值达到特定阈值:

class ExecuteTradeAction extends ReduxAction<AppState> {
  final double targetPrice;

  ExecuteTradeAction(this.targetPrice);

  @override
  Future<AppState?> reduce() async {
    // 等待直到股票价格达到目标
    await waitCondition((state) => state.stockPrice >= targetPrice);

    // 在或高于目标价格执行交易
    return state.copy(
      tradeExecuted: true,
      executionPrice: state.stockPrice,
    );
  }
}

协调actions之间

使用waitCondition()来协调依赖的actions:

class ProcessOrderAction extends ReduxAction<AppState> {
  @override
  Future<AppState?> reduce() async {
    // 调度并行数据加载
    dispatch(LoadInventoryAction());
    dispatch(LoadPricingAction());

    // 等待两者完成
    await waitCondition((state) =>
      state.inventoryLoaded && state.pricingLoaded
    );

    // 两者现在可用 - 继续订单处理
    final total = calculateTotal(state.inventory, state.pricing);
    return state.copy(orderTotal: total);
  }
}

实现条件工作流

创建多步骤工作流,等待用户输入或外部事件:

class CheckoutWorkflowAction extends ReduxAction<AppState> {
  @override
  Future<AppState?> reduce() async {
    // 步骤1:等待购物车准备就绪
    await waitCondition((state) => state.cart.isNotEmpty);

    // 步骤2:开始支付处理
    dispatch(InitiatePaymentAction());

    // 步骤3:等待支付确认
    await waitCondition((state) =>
      state.paymentStatus == PaymentStatus.confirmed ||
      state.paymentStatus == PaymentStatus.failed
    );

    if (state.paymentStatus == PaymentStatus.failed) {
      throw UserException('支付失败。请重试。');
    }

    // 步骤4:完成订单
    return state.copy(orderCompleted: true);
  }
}

使用返回值

waitCondition()返回导致条件变为true的action:

class MonitorPriceAction extends ReduxAction<AppState> {
  @override
  Future<AppState?> reduce() async {
    // 等待价格变化并获取改变它的action
    final triggeringAction = await waitCondition(
      (state) => state.price > 100,
    );

    // 可以检查哪个action触发了条件
    if (triggeringAction is PriceUpdateAction) {
      print('价格更新由: ${triggeringAction.source}');
    }

    return state.copy(alertTriggered: true);
  }
}

使用completeImmediately参数

控制当条件已经满足时的行为:

class WaitForNewDataAction extends ReduxAction<AppState> {
  @override
  Future<AppState?> reduce() async {
    // completeImmediately: false 意味着等待一个新的状态变化
    // 即使条件当前已经满足
    await waitCondition(
      (state) => state.dataVersion > 0,
      completeImmediately: false,  // 等待新数据
    );

    return state.copy(dataProcessed: true);
  }
}

设置超时

用自定义超时防止无限等待:

class TimeSensitiveAction extends ReduxAction<AppState> {
  @override
  Future<AppState?> reduce() async {
    try {
      // 等待最多5秒条件满足
      await waitCondition(
        (state) => state.isReady,
        timeoutMillis: 5000,
      );
    } catch (e) {
      // 超时超出 - 优雅处理
      throw UserException('操作超时。请重试。');
    }

    return state.copy(processed: true);
  }
}

从Store使用waitCondition()

在测试或widgets中,直接在store上调用waitCondition()

// 在测试中
test('等待数据加载', () async {
  var store = Store<AppState>(initialState: AppState.initial());

  store.dispatch(LoadDataAction());

  // 等待加载完成
  await store.waitCondition((state) => state.isLoaded);

  expect(store.state.data, isNotNull);
});

使用waitCondition()进行测试

waitCondition()在测试中很有用,等待预期状态:

test('在库存加载后处理订单', () async {
  var store = Store<AppState>(
    initialState: AppState(inventoryLoaded: false),
  );

  // 开始处理
  store.dispatch(ProcessOrderAction());

  // 模拟库存加载
  await Future.delayed(Duration(milliseconds: 100));
  store.dispatch(LoadInventoryCompleteAction());

  // 等待订单处理完成
  await store.waitCondition((state) => state.orderProcessed);

  expect(store.state.orderTotal, greaterThan(0));
});

与其他等待方法比较

方法 使用案例
waitCondition() 等待状态满足谓词
dispatchAndWait() 等待特定action完成
waitAllActions([]) 等待所有当前actions完成
waitActionType() 等待特定类型的action

常见模式

等待初始化

class AppStartupAction extends ReduxAction<AppState> {
  @override
  Future<AppState?> reduce() async {
    dispatch(LoadUserAction());
    dispatch(LoadSettingsAction());
    dispatch(LoadCacheAction());

    // 等待所有初始化完成
    await waitCondition((state) =>
      state.user != null &&
      state.settings != null &&
      state.cacheReady
    );

    return state.copy(appReady: true);
  }
}

等待用户确认

class DeleteAccountAction extends ReduxAction<AppState> {
  @override
  Future<AppState?> reduce() async {
    // 显示确认对话框
    dispatch(ShowConfirmationDialogAction(
      message: '你确定要删除你的账户吗?',
    ));

    // 等待用户响应
    await waitCondition((state) =>
      state.confirmationResult != null
    );

    if (state.confirmationResult != true) {
      return null; // 用户取消
    }

    // 继续删除
    await api.deleteAccount();
    return state.copy(accountDeleted: true);
  }
}

参考链接

文档中的URLs: