asyncredux-setup
Initialize, setup and configure AsyncRedux in a Flutter app. Use it whenever starting a new AsyncRedux project, or when the user requests.
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
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/asyncredux-setup/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How asyncredux-setup Compares
| Feature / Agent | asyncredux-setup | 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?
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
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
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
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-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.