asyncredux-setup

Initialize, setup and configure AsyncRedux in a Flutter app. Use it whenever starting a new AsyncRedux project, or when the user requests.

16 stars

Best use case

asyncredux-setup is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Initialize, setup and configure AsyncRedux in a Flutter app. Use it whenever starting a new AsyncRedux project, or when the user requests.

Teams using asyncredux-setup 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

$curl -o ~/.claude/skills/asyncredux-setup/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/design/asyncredux-setup/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/asyncredux-setup/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How asyncredux-setup Compares

Feature / Agentasyncredux-setupStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Initialize, setup and configure AsyncRedux in a Flutter app. Use it whenever starting a new AsyncRedux project, or when the user requests.

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

# AsyncRedux Setup

## Adding the Dependency

Add AsyncRedux to your `pubspec.yaml`:

```yaml
dependencies:
  async_redux: ^25.6.1
```

Check [pub.dev](https://pub.dev/packages/async_redux) for the latest version.

## Creating the State Class

Create an immutable `AppState` class (in file `app_state.dart`) with:

* `copy()` method
* `==` equals method
* `hashCode` method
* `initialState()` static factory

If the app is new, and you don't have any state yet, create an empty `AppState`:

```dart
@immutable
class AppState {
  AppState();
  static AppState initialState() => AppState();
  AppState copy() => AppState();
  
  @override
  bool operator ==(Object other) =>
    identical(this, other) ||
    other is AppState && runtimeType == other.runtimeType;

  @override
  int get hashCode => 0;
}
```

If there is existing state, create the `AppState` that incorporates that state.
This is an example:

```dart
@immutable
class AppState {
  final String name;
  final int age;
  AppState({required this.name, required this.age});

  static AppState initialState() => AppState(name: "", age: 0);

  AppState copy({String? name, int? age}) => AppState(
    name: name ?? this.name,
    age: age ?? this.age,
  );
  
  @override
  bool operator ==(Object other) =>
    identical(this, other) ||
    other is AppState &&
      runtimeType == other.runtimeType &&
      name == other.name &&
      age == other.age;

  @override
  int get hashCode => Object.hash(name, age);
}

```

All fields must be `final` (immutable). Add additional helper methods as needed:

```dart
AppState withName(String name) => copy(name: name);
AppState withAge(int age) => copy(age: age);
```

## Creating the Store

Find the place where you initialize your app (usually in `main.dart`),
and import your `AppState` class (adapt the path as needed) and the AsyncRedux package:

```dart
import 'app_state.dart'; 
import 'package:async_redux/async_redux.dart';
```

Create the store with your initial state. Note that `PersistorDummy`,
`GlobalWrapErrorDummy`, and `ConsoleActionObserver` are provided by AsyncRedux for basic
setups. In the future these can be replaced with custom implementations as needed.

```dart
late Store store;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Create the persistor, and try to read any previously saved state.
  var persistor = PersistorDummy<AppState>();
  AppState? initialState = await persistor.readState();
  
  // If there is no saved state, create a new empty one and save it.
  if (initialState == null) {
    initialState = AppState.initialState();
    await persistor.saveInitialState(initialState);
  }
    
  // Create the store.
  store = Store<AppState>(
    initialState: initialState,
    persistor: persistor,
    globalWrapError: GlobalWrapErrorDummy(),    
    actionObservers: [ConsoleActionObserver()],
  );

  runApp(...);
}
```

## Wrapping with StoreProvider

Wrap your app with `StoreProvider` to make the store accessible.
Find the root of the widget tree of the app, and add it above `MaterialApp` (or
`CupertinoApp`, adapting as needed). Note you will need to import the `store` too.

```dart
import 'package:async_redux/async_redux.dart';

Widget build(context) {
  return StoreProvider<AppState>(
    store: store,
    child: MaterialApp( ... ),
  );
}
```

## Required Context Extensions

You **must** add this extension to your file containing `AppState` (this is required for
easier state access in widgets):

```dart
extension BuildContextExtension on BuildContext {
  AppState get state => getState<AppState>();

  AppState read() => getRead<AppState>();

  R select<R>(R Function(AppState state) selector) =>
      getSelect<AppState, R>(selector);

  R? event<R>(Evt<R> Function(AppState state) selector) =>
      getEvent<AppState, R>(selector);
}
```

## Required base action

Create file `app_action.dart` with this abstract class extending `ReduxAction<AppState>`:

```dart
/// All actions extend this class.
abstract class AppAction extends ReduxAction<AppState> {

ActionSelect get select => ActionSelect(state);
}

// Dedicated selector class to keep the base action clean.
class ActionSelect {
  final AppState state;
  ActionSelect(this.state);
}
```

## Update CLAUDE.md

Add the following information to the project's `CLAUDE.md`, so that all actions extend
this
base action:

```markdown
## Base Action

All actions should extend `AppAction` instead of `ReduxAction<AppState>`. 
There is a dedicated selector class called `ActionSelect` to keep the base action clean,
by namespacing selectors under `select` and enabling IDE autocompletion. Example:

  ```dart
  class ProcessItem extends AppAction {
    final String itemId;
    ProcessItem(this.itemId);
    
    @override
    AppState reduce() {
      // IDE autocomplete shows: select.findById, select.completed, etc.
      final item = select.findById(itemId);
      // ...
    }
  }
  ```

```

Related Skills

asyncredux-wait-fail-succeed

16
from diegosouzapw/awesome-omni-skill

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-wait-condition

16
from diegosouzapw/awesome-omni-skill

Use `waitCondition()` inside actions to pause execution until state meets criteria. Covers waiting for price thresholds, coordinating between actions, and implementing conditional workflows.

asyncredux-user-exceptions

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

Creates AsyncRedux (Flutter) synchronous actions that update state immediately by implementing reduce() to return a new state.

asyncredux-streams-timers

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

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-selectors

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

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.