Skip to content
asyncredux-action-status logo

ActionStatus in AsyncRedux

asyncredux-action-status

Checks an AsyncRedux (Flutter) action's completion status using ActionStatus right after the dispatch returns. Use only when you need to know whether an action completed, whether it failed with an error, what error it produced, or how to navigate based on success or failure.

SKILL.md

Full skill instructions

ActionStatus in AsyncRedux

The ActionStatus object provides information about whether an action completed successfully or encountered errors. It is returned by dispatchAndWait() and related methods.

Getting ActionStatus

Use dispatchAndWait() to get the status after an action completes:

var status = await dispatchAndWait(MyAction());

From within an action, you can also use:

var status = await dispatchAndWait(SomeOtherAction());

ActionStatus Properties

Completion Status

  • isCompleted: Returns true if the action has finished executing (whether successful or failed)
  • isCompletedOk: Returns true if the action finished without errors in both before() and reduce() methods
  • isCompletedFailed: Returns true if the action encountered errors (opposite of isCompletedOk)

Error Information

  • originalError: The error originally thrown by before() or reduce(), before any modification
  • wrappedError: The error after processing by the action's wrapError() method

Execution Tracking

These properties track which lifecycle methods have completed:

  • hasFinishedMethodBefore: Returns true if the before() method completed
  • hasFinishedMethodReduce: Returns true if the reduce() method completed
  • hasFinishedMethodAfter: Returns true if the after() method completed

Note: The execution tracking properties are primarily meant for testing and debugging. In production code, focus on isCompletedOk and isCompletedFailed.

Common Use Cases

Conditional Navigation After Success

The most common production use is checking if an action succeeded before navigating:

// In a widget callback
Future<void> _onSavePressed() async {
  var status = await context.dispatchAndWait(SaveFormAction());
  if (status.isCompletedOk) {
    Navigator.pop(context);
  }
}

Another example with push navigation:

Future<void> _onLoginPressed() async {
  var status = await context.dispatchAndWait(LoginAction(
    email: emailController.text,
    password: passwordController.text,
  ));

  if (status.isCompletedOk) {
    Navigator.pushReplacementNamed(context, '/​home');
  }
  // If failed, the error will be shown via UserExceptionDialog
}

Testing Action Errors

Use ActionStatus to verify that actions throw expected errors:

test('MyAction fails with invalid input', () async {
  var store = Store<AppState>(initialState: AppState.initial());

  var status = await store.dispatchAndWait(MyAction(value: -1));

  expect(status.isCompletedFailed, isTrue);
  expect(status.wrappedError, isA<UserException>());
  expect((status.wrappedError as UserException).msg, "Value must be positive");
});

Testing Action Success

test('SaveAction completes successfully', () async {
  var store = Store<AppState>(initialState: AppState.initial());

  var status = await store.dispatchAndWait(SaveAction(data: validData));

  expect(status.isCompletedOk, isTrue);
  expect(store.state.saved, isTrue);
});

Checking Original vs Wrapped Error

When your action uses wrapError() to transform errors, you can inspect both:

class MyAction extends AppAction {
  @override
  Future<AppState?> reduce() async {
    throw Exception('Network error');
  }

  @override
  Object? wrapError(Object error, StackTrace stackTrace) {
    return UserException('Could not save. Please try again.');
  }
}

// In test:
var status = await store.dispatchAndWait(MyAction());
expect(status.originalError, isA<Exception>()); // The original Exception
expect(status.wrappedError, isA<UserException>()); // The wrapped UserException

Action Lifecycle and Status

The action lifecycle runs in this order:

  1. before() - Runs first, can be used for preconditions
  2. reduce() - Runs second (only if before() succeeded)
  3. after() - Runs last, always executes (like a finally block)

The isCompletedOk property is true only if both before() and reduce() completed without errors. Note that errors in after() do not affect isCompletedOk.

If before() throws an error, reduce() will not run, but after() will still execute.

Best Practices

  1. Use state changes for UI updates: In production, prefer checking state changes rather than action status. Reserve ActionStatus for cases where you need to perform side effects (like navigation) based on success/​failure.

  2. Use isCompletedOk for navigation: The common pattern is to navigate only after an action succeeds:

    if (status.isCompletedOk) Navigator.pop(context);
    
  3. Use wrappedError in tests: When testing error handling, check wrappedError to see what the user will actually see (after wrapError() processing).

  4. Use originalError for debugging: When you need to see the underlying error before any transformation, use originalError.

References

URLs from the documentation:

More Other skills

Delegate independent tasks to specialized agents working concurrently with isolated context.

295.4K 206.3K
View

Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.

179.7K 100.1K
View

Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.

179.7K 89.5K
View

A set of resources to help me write all kinds of internal communications, using the formats that my company likes to use. Claude should use this skill whenever asked to write some sort of internal communications (status reports, leadership updates, 3P updates, company newsletters, FAQs, incident reports, project updates, etc.).

179.7K 76.1K
View

Fundamental design principles for writing maintainable, testable Python code.

40.2K 21.9K
View

Modern responsive layouts using container queries, fluid typography, CSS Grid, and mobile-first strategies.

40.2K 20K
View

Generate Playwright tests from scenarios using interactive browser exploration and validation.

39.7K 18.2K
View

Modern React state management with Redux Toolkit, Zustand, Jotai, and React Query for every state category.

40.2K 14.7K
View

GDPR-compliant data handling with consent management, data subject rights, and privacy controls.

40.2K 14.3K
View

Python error handling patterns including input validation, exception hierarchies, and partial failure handling. Use when implementing validation logic, designing exception strategies, handling batch processing failures, or building robust APIs.

40.2K 13.5K
View

Detailed multi-file refactor planning with safety checks and rollback guidance.

39.7K 13K
View