name: asyncredux-wait-condition
description: 在actions中使用waitCondition()来暂停执行,直到状态满足条件。涵盖等待价格阈值、协调actions之间的依赖以及实现条件工作流。
使用waitCondition()等待状态条件
waitCondition()方法暂停执行,直到应用状态满足特定条件。它在Store和ReduxAction类中都可用。
方法签名
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:
- https://asyncredux.com/flutter/miscellaneous/wait-condition
- https://asyncredux.com/flutter/miscellaneous/advanced-waiting
- https://asyncredux.com/flutter/advanced-actions/redux-action
- https://asyncredux.com/flutter/testing/store-tester
- https://asyncredux.com/flutter/testing/dispatch-wait-and-expect
- https://asyncredux.com/flutter/basics/async-actions
- https://asyncredux.com/flutter/basics/dispatching-actions
- https://asyncredux.com/flutter/advanced-actions/before-and-after-the-reducer