Claude-skill-registry asyncredux-sync-actions
Creates AsyncRedux (Flutter) synchronous actions that update state immediately by implementing reduce() to return a new state.
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-sync-actions" ~/.claude/skills/majiayu000-claude-skill-registry-asyncredux-sync-actions && rm -rf "$T"
manifest:
skills/data/asyncredux-sync-actions/SKILL.mdsource content
AsyncRedux Sync Actions
Basic Sync Action Structure
A synchronous action returns
AppState? from its reduce() method. The action completes
immediately and state updates right away.
class Increment extends ReduxAction<AppState> { @override AppState? reduce() => state.copy(counter: state.counter + 1); }
Key Components
Extending ReduxAction
Every action extends
ReduxAction<AppState>:
class MyAction extends ReduxAction<AppState> { @override AppState? reduce() { // Return new state } }
The state
Getter
stateInside
reduce(), access current state via the state getter:
class ToggleFlag extends ReduxAction<AppState> { @override AppState? reduce() => state.copy(flag: !state.flag); }
Passing Parameters via Constructor
Pass data to actions through constructor fields:
class SetName extends ReduxAction<AppState> { final String name; SetName(this.name); @override AppState? reduce() => state.copy(name: name); } class IncrementBy extends ReduxAction<AppState> { final int amount; IncrementBy({required this.amount}); @override AppState? reduce() => state.copy(counter: state.counter + amount); }
Modifying Nested State
For nested state objects, create the new nested object first:
class UpdateUserName extends ReduxAction<AppState> { final String name; UpdateUserName(this.name); @override AppState? reduce() { var newUser = state.user.copy(name: name); return state.copy(user: newUser); } }
Dispatching Sync Actions
From Widgets
Use context extensions:
// Fire and forget context.dispatch(Increment()); // With parameters context.dispatch(SetName('Alice')); context.dispatch(IncrementBy(amount: 5));
Immediate State Update
Sync actions update state immediately:
print(store.state.counter); // 2 store.dispatch(IncrementBy(amount: 3)); print(store.state.counter); // 5
Guaranteed Sync with dispatchSync()
The
dispatchSync() throws StoreException if the action is async. Otherwise, it
behaves exactly like dispatch().
Use
dispatchSync() only in the rare cases when you must ensure the action is synchronous
because you need the state to be applied right after the dispatch returns.
context.dispatchSync(Increment());
From Other Actions
Actions can dispatch other actions:
class ResetAndIncrement extends ReduxAction<AppState> { @override AppState? reduce() { dispatch(Reset()); dispatch(Increment()); return null; // This action itself doesn't change state } }
Returning Null (No State Change)
Return
null when you don't need to change state:
class LogCurrentState extends ReduxAction<AppState> { @override AppState? reduce() { print('Current counter: ${state.counter}'); return null; // No state change } }
Conditional state changes:
class IncrementIfPositive extends ReduxAction<AppState> { final int amount; IncrementIfPositive(this.amount); @override AppState? reduce() { if (amount <= 0) return null; return state.copy(counter: state.counter + amount); } }
Action Simplification with Base Class
Create a base action class to reduce boilerplate:
// Define once abstract class AppAction extends ReduxAction<AppState> {} // Use everywhere class Increment extends AppAction { @override AppState? reduce() => state.copy(counter: state.counter + 1); } class SetName extends AppAction { final String name; SetName(this.name); @override AppState? reduce() => state.copy(name: name); }
You can add shared functionality to your base class:
abstract class AppAction extends ReduxAction<AppState> { // Shortcuts to state parts User get user => state.user; Settings get settings => state.settings; } class UpdateEmail extends AppAction { final String email; UpdateEmail(this.email); @override AppState? reduce() => state.copy( user: user.copy(email: email), // Uses shortcut ); }
Return Type Warning
The
reduce() method signature is FutureOr<AppState?>. For sync actions, always return
AppState? directly:
// CORRECT - Sync action AppState? reduce() => state.copy(counter: state.counter + 1); // WRONG - Don't return FutureOr directly FutureOr<AppState?> reduce() => state.copy(counter: state.counter + 1);
If you return
FutureOr<AppState?> directly, AsyncRedux cannot determine if the action is
sync or async and will throw a StoreException.
Complete Example
// State class AppState { final int counter; final String name; AppState({required this.counter, required this.name}); static AppState initialState() => AppState(counter: 0, name: ''); AppState copy({int? counter, String? name}) => AppState( counter: counter ?? this.counter, name: name ?? this.name, ); } // Base action abstract class AppAction extends ReduxAction<AppState> {} // Sync actions class Increment extends AppAction { @override AppState? reduce() => state.copy(counter: state.counter + 1); } class Decrement extends AppAction { @override AppState? reduce() => state.copy(counter: state.counter - 1); } class IncrementBy extends AppAction { final int amount; IncrementBy(this.amount); @override AppState? reduce() => state.copy(counter: state.counter + amount); } class SetName extends AppAction { final String name; SetName(this.name); @override AppState? reduce() => state.copy(name: name); } class Reset extends AppAction { @override AppState? reduce() => AppState.initialState(); } // Usage in widget ElevatedButton( onPressed: () => context.dispatch(IncrementBy(5)), child: Text('Add 5'), )
References
URLs from the documentation:
- https://asyncredux.com/flutter/basics/sync-actions
- https://asyncredux.com/flutter/basics/actions-and-reducers
- https://asyncredux.com/flutter/advanced-actions/redux-action
- https://asyncredux.com/flutter/basics/dispatching-actions
- https://asyncredux.com/flutter/basics/action-simplification
- https://asyncredux.com/flutter/basics/changing-state-is-optional