Claude-skill-registry asyncredux-setup
Initialize, setup and configure AsyncRedux in a Flutter app. Use it whenever starting a new AsyncRedux project, or when the user requests.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/asyncredux-setup" ~/.claude/skills/majiayu000-claude-skill-registry-asyncredux-setup && rm -rf "$T"
manifest:
skills/data/asyncredux-setup/SKILL.mdsource content
AsyncRedux Setup
Adding the Dependency
Add AsyncRedux to your
pubspec.yaml:
dependencies: async_redux: ^25.6.1
Check pub.dev for the latest version.
Creating the State Class
Create an immutable
AppState class (in file app_state.dart) with:
methodcopy()
equals method==
methodhashCode
static factoryinitialState()
If the app is new, and you don't have any state yet, create an empty
AppState:
@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:
@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:
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:
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.
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.
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):
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>:
/// 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:
## 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); // ... } }