asyncredux-wait-condition
Use `waitCondition()` inside actions to pause execution until state meets criteria. Covers waiting for price thresholds, coordinating between actions, and implementing conditional workflows.
Best use case
asyncredux-wait-condition is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Use `waitCondition()` inside actions to pause execution until state meets criteria. Covers waiting for price thresholds, coordinating between actions, and implementing conditional workflows.
Teams using asyncredux-wait-condition should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/asyncredux-wait-condition/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How asyncredux-wait-condition Compares
| Feature / Agent | asyncredux-wait-condition | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Use `waitCondition()` inside actions to pause execution until state meets criteria. Covers waiting for price thresholds, coordinating between actions, and implementing conditional workflows.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Waiting for State Conditions with waitCondition()
The `waitCondition()` method pauses execution until the application state satisfies a specific condition. It's available on both the `Store` and `ReduxAction` classes.
## Method Signature
```dart
Future<ReduxAction<St>?> waitCondition(
bool Function(St) condition, {
bool completeImmediately = true,
int? timeoutMillis,
});
```
**Parameters:**
- **condition**: A function that takes the current state and returns `true` when the desired condition is met
- **completeImmediately**: If `true` (default), completes immediately when the condition is already satisfied. If `false`, waits for a state change to meet the condition
- **timeoutMillis**: Maximum time to wait (defaults to 10 minutes). Set to `-1` to disable timeout
**Returns:** The action that triggered the condition to become true, or `null` if condition was already met.
## Basic Usage Inside an Action
Use `waitCondition()` when your action needs to wait for a prerequisite state before proceeding:
```dart
class AddAppointmentAction extends ReduxAction<AppState> {
final String title;
final DateTime date;
AddAppointmentAction({required this.title, required this.date});
@override
Future<AppState?> reduce() async {
// Ensure calendar exists before adding appointment
if (state.calendar == null) {
dispatch(CreateCalendarAction());
// Wait until calendar is available
await waitCondition((state) => state.calendar != null);
}
// Now safe to add the appointment
return state.copy(
calendar: state.calendar!.addAppointment(
Appointment(title: title, date: date),
),
);
}
}
```
## Waiting for Value Thresholds
Wait for numeric values to reach specific thresholds:
```dart
class ExecuteTradeAction extends ReduxAction<AppState> {
final double targetPrice;
ExecuteTradeAction(this.targetPrice);
@override
Future<AppState?> reduce() async {
// Wait until stock price reaches target
await waitCondition((state) => state.stockPrice >= targetPrice);
// Execute the trade at or above target price
return state.copy(
tradeExecuted: true,
executionPrice: state.stockPrice,
);
}
}
```
## Coordinating Between Actions
Use `waitCondition()` to coordinate dependent actions:
```dart
class ProcessOrderAction extends ReduxAction<AppState> {
@override
Future<AppState?> reduce() async {
// Dispatch parallel data loading
dispatch(LoadInventoryAction());
dispatch(LoadPricingAction());
// Wait for both to complete
await waitCondition((state) =>
state.inventoryLoaded && state.pricingLoaded
);
// Both are now available - proceed with order processing
final total = calculateTotal(state.inventory, state.pricing);
return state.copy(orderTotal: total);
}
}
```
## Implementing Conditional Workflows
Create multi-step workflows that wait for user input or external events:
```dart
class CheckoutWorkflowAction extends ReduxAction<AppState> {
@override
Future<AppState?> reduce() async {
// Step 1: Wait for cart to be ready
await waitCondition((state) => state.cart.isNotEmpty);
// Step 2: Start payment processing
dispatch(InitiatePaymentAction());
// Step 3: Wait for payment confirmation
await waitCondition((state) =>
state.paymentStatus == PaymentStatus.confirmed ||
state.paymentStatus == PaymentStatus.failed
);
if (state.paymentStatus == PaymentStatus.failed) {
throw UserException('Payment failed. Please try again.');
}
// Step 4: Complete the order
return state.copy(orderCompleted: true);
}
}
```
## Using the Return Value
`waitCondition()` returns the action that caused the condition to become true:
```dart
class MonitorPriceAction extends ReduxAction<AppState> {
@override
Future<AppState?> reduce() async {
// Wait for price change and get the action that changed it
final triggeringAction = await waitCondition(
(state) => state.price > 100,
);
// Can inspect which action triggered the condition
if (triggeringAction is PriceUpdateAction) {
print('Price updated by: ${triggeringAction.source}');
}
return state.copy(alertTriggered: true);
}
}
```
## Using completeImmediately Parameter
Control behavior when the condition is already met:
```dart
class WaitForNewDataAction extends ReduxAction<AppState> {
@override
Future<AppState?> reduce() async {
// completeImmediately: false means wait for a NEW state change
// even if condition is currently satisfied
await waitCondition(
(state) => state.dataVersion > 0,
completeImmediately: false, // Wait for fresh data
);
return state.copy(dataProcessed: true);
}
}
```
## Setting Timeouts
Prevent indefinite waiting with custom timeouts:
```dart
class TimeSensitiveAction extends ReduxAction<AppState> {
@override
Future<AppState?> reduce() async {
try {
// Wait maximum 5 seconds for condition
await waitCondition(
(state) => state.isReady,
timeoutMillis: 5000,
);
} catch (e) {
// Timeout exceeded - handle gracefully
throw UserException('Operation timed out. Please try again.');
}
return state.copy(processed: true);
}
}
```
## Using waitCondition() from the Store
In tests or widgets, call `waitCondition()` directly on the store:
```dart
// In a test
test('waits for data to load', () async {
var store = Store<AppState>(initialState: AppState.initial());
store.dispatch(LoadDataAction());
// Wait for loading to complete
await store.waitCondition((state) => state.isLoaded);
expect(store.state.data, isNotNull);
});
```
## Testing with waitCondition()
`waitCondition()` is useful in tests to wait for expected state:
```dart
test('processes order after inventory loads', () async {
var store = Store<AppState>(
initialState: AppState(inventoryLoaded: false),
);
// Start the process
store.dispatch(ProcessOrderAction());
// Simulate inventory loading
await Future.delayed(Duration(milliseconds: 100));
store.dispatch(LoadInventoryCompleteAction());
// Wait for order processing to complete
await store.waitCondition((state) => state.orderProcessed);
expect(store.state.orderTotal, greaterThan(0));
});
```
## Comparison with Other Wait Methods
| Method | Use Case |
|--------|----------|
| `waitCondition()` | Wait for state to satisfy a predicate |
| `dispatchAndWait()` | Wait for a specific action to complete |
| `waitAllActions([])` | Wait for all current actions to finish |
| `waitActionType()` | Wait for an action of a specific type |
## Common Patterns
### Wait for Initialization
```dart
class AppStartupAction extends ReduxAction<AppState> {
@override
Future<AppState?> reduce() async {
dispatch(LoadUserAction());
dispatch(LoadSettingsAction());
dispatch(LoadCacheAction());
// Wait for all initialization to complete
await waitCondition((state) =>
state.user != null &&
state.settings != null &&
state.cacheReady
);
return state.copy(appReady: true);
}
}
```
### Wait for User Confirmation
```dart
class DeleteAccountAction extends ReduxAction<AppState> {
@override
Future<AppState?> reduce() async {
// Show confirmation dialog
dispatch(ShowConfirmationDialogAction(
message: 'Are you sure you want to delete your account?',
));
// Wait for user response
await waitCondition((state) =>
state.confirmationResult != null
);
if (state.confirmationResult != true) {
return null; // User cancelled
}
// Proceed with deletion
await api.deleteAccount();
return state.copy(accountDeleted: true);
}
}
```
## References
URLs from the documentation:
- 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-reducerRelated Skills
asyncredux-wait-fail-succeed
Show loading states and handle action failures in widgets. Covers `isWaiting(ActionType)` for spinners, `isFailed(ActionType)` for error states, `exceptionFor(ActionType)` for error messages, and `clearExceptionFor()` to reset failure states.
asyncredux-user-exceptions
Handle user-facing errors with UserException. Covers throwing UserException from actions, setting up UserExceptionDialog, customizing error dialogs with `onShowUserExceptionDialog`, and using UserExceptionAction for non-interrupting error display.
asyncredux-sync-actions
Creates AsyncRedux (Flutter) synchronous actions that update state immediately by implementing reduce() to return a new state.
asyncredux-streams-timers
Manage Streams and Timers with AsyncRedux. Covers creating actions to start/stop streams, storing stream subscriptions in store props, dispatching actions from stream callbacks, and proper cleanup with disposeProps().
asyncredux-state-access
Access store state in widgets using `context.state`, `context.select()`, and `context.read()`. Covers when to use each method, setting up BuildContext extensions, and optimizing widget rebuilds with selective state access.
asyncredux-setup
Initialize, setup and configure AsyncRedux in a Flutter app. Use it whenever starting a new AsyncRedux project, or when the user requests.
asyncredux-selectors
Create and cache selectors for efficient state access. Covers writing selector functions, caching with `cache1` and `cache2`, the reselect pattern, and avoiding repeated computations in widgets.
asyncredux-persistence
Implement local state persistence using Persistor. Covers creating a custom Persistor class, implementing `readState()`, `persistDifference()`, `deleteState()`, using LocalPersist helper, throttling saves, and pausing/resuming persistence with app lifecycle.
asyncredux-optimistic-update-mixin
Add the OptimisticUpdate mixin for instant UI feedback before server confirmation. Covers immediate state changes, automatic rollback on failure, and optionally notifying users of rollback.
asyncredux-navigation
Handle navigation through actions using NavigateAction. Covers setting up the navigator key, dispatching NavigateAction for push/pop/replace, and testing navigation in isolation.
asyncredux-events
Use the Event class to interact with Flutter's stateful widgets (TextField, ListView, etc.). Covers creating Event objects in state, consuming events with `context.event()`, scrolling lists, changing text fields, and the event lifecycle.
asyncredux-dependency-injection
Inject dependencies into actions using the environment pattern. Covers creating an Environment class, passing it to the Store, accessing `env` from actions, and using dependency injection for testability.