.claude/skills/asyncredux-debounce-mixin/SKILL.md
Add the Debounce mixin to wait for user input pauses before acting. Covers setting the `debounce` duration, implementing search-as-you-type, and avoiding excessive API calls during rapid input.
npx skillsauth add marcglasberg/async_redux asyncredux-debounce-mixinInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The Debounce mixin delays action execution until after a period of inactivity. Each new dispatch resets the timer, so the action only runs once dispatching stops for the specified duration. This is ideal for search-as-you-type functionality and avoiding excessive API calls during rapid user input.
Add the Debounce mixin to your action class:
class SearchText extends AppAction with Debounce {
final String searchTerm;
SearchText(this.searchTerm);
Future<AppState?> reduce() async {
var response = await http.get(
Uri.parse('https://example.com/?q=${Uri.encodeComponent(searchTerm)}')
);
return state.copy(searchResult: response.body);
}
}
When the user types quickly, each keystroke dispatches SearchText. The mixin delays execution, and each new dispatch resets the timer. The API call only happens once the user stops typing for the debounce period.
The default debounce period is 333 milliseconds. Override the debounce getter to customize:
class SearchText extends AppAction with Debounce {
final String searchTerm;
SearchText(this.searchTerm);
// Wait 1 second of inactivity before executing
int get debounce => 1000;
Future<AppState?> reduce() async {
var response = await http.get(
Uri.parse('https://example.com/?q=${Uri.encodeComponent(searchTerm)}')
);
return state.copy(searchResult: response.body);
}
}
By default, all instances of a debounced action share the same lock. Override lockBuilder() to create independent debounce periods for different action instances:
class SearchField extends AppAction with Debounce {
final String fieldId;
final String searchTerm;
SearchField(this.fieldId, this.searchTerm);
// Each fieldId gets its own independent debounce timer
Object? lockBuilder() => fieldId;
Future<AppState?> reduce() async {
// Search logic here
}
}
This enables multiple search fields to operate independently, each with their own debounce timer.
These two mixins serve different purposes:
| Mixin | Behavior | Best For | |-------|----------|----------| | Throttle | Runs immediately on first dispatch, then blocks subsequent dispatches for the period | Rate-limiting actions that should execute right away (e.g., refresh button) | | Debounce | Waits for quiet time, only runs after dispatches stop | Waiting for user to finish input (e.g., search-as-you-type) |
Throttle: "Execute now, then wait before allowing again" Debounce: "Wait until activity stops, then execute"
Debounce can be combined with:
CheckInternetNoDialogAbortWhenNoInternetNonReentrantFreshThrottleDebounce cannot be combined with:
RetryUnlimitedRetriesUnlimitedRetryCheckInternetOptimisticCommandOptimisticSyncOptimisticSyncWithPushServerPushURLs from the documentation:
data-ai
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.
data-ai
Use `waitCondition()` inside actions to pause execution until state meets criteria. Covers waiting for price thresholds, coordinating between actions, and implementing conditional workflows.
testing
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.
tools
Implement undo/redo functionality using state observers. Covers recording state history with stateObserver, creating a RecoverStateAction, implementing undo for the full state or partial state, and managing history limits.