بنقرة واحدة
add-debounce
Add debounce to delay method execution until after a period of inactivity for search or validation
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Add debounce to delay method execution until after a period of inactivity for search or validation
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Add custom error handling with catchError to a mix() call for logging, error conversion, or suppression
Add internet connectivity checking before executing a Cubit method with optional retry
Add EffectQueue to state for triggering multiple sequential one-time UI effects
Add Effect fields to state class for one-time UI notifications like snackbars, navigation, or form clearing
Add error state handling to widgets using context.isFailed() and context.getException()
Add freshness caching to prevent redundant method executions within a time period
| name | add-debounce |
| description | Add debounce to delay method execution until after a period of inactivity for search or validation |
This skill delays method execution until after a period of inactivity, useful for search-as-you-type and form validation.
Adds the debounce parameter to a mix() call so that:
Ask the user which Cubit method needs debouncing, or identify methods that:
Add debounce: debounce to the mix() call:
import 'package:bloc_superpowers/bloc_superpowers.dart';
class SearchCubit extends Cubit<SearchState> {
SearchCubit() : super(const SearchState());
void search(String query) => mix(
key: this,
debounce: debounce, // Add this line (default: 300ms)
() async {
final results = await api.search(query);
emit(state.copyWith(results: results));
},
);
}
The default debounce duration is 300 milliseconds. Customize as needed:
void search(String query) => mix(
key: this,
debounce: debounce(duration: 500.millis), // Wait 500ms of inactivity
() async {
final results = await api.search(query);
emit(state.copyWith(results: results));
},
);
User types: "h" → "he" → "hel" → "hell" → "hello"
↓ ↓ ↓ ↓ ↓
reset reset reset reset timer starts
↓
300ms passes
↓
search("hello") executes
Instead of 5 API calls, only 1 call is made with the final value.
debounce // 300ms (default)
debounce(duration: 100.millis) // 100ms (faster response)
debounce(duration: 500.millis) // 500ms (more delay)
debounce(duration: 1.sec) // 1 second
Different parameters can have separate debounce timers:
void searchInCategory(String category, String query) => mix(
key: this,
debounce: debounce(key: (SearchCubit, category)),
() async {
final results = await api.searchInCategory(category, query);
emit(state.copyWith(results: results));
},
);
With this setup:
class SearchCubit extends Cubit<SearchState> {
SearchCubit() : super(const SearchState());
void search(String query) => mix(
key: this,
debounce: debounce(duration: 300.millis),
() async {
if (query.isEmpty) {
emit(state.copyWith(results: []));
return;
}
final results = await api.search(query);
emit(state.copyWith(results: results));
},
);
}
// In widget
TextField(
onChanged: (value) => context.read<SearchCubit>().search(value),
)
void validateEmail(String email) => mix(
key: ValidateEmail,
debounce: debounce(duration: 500.millis),
() async {
final isValid = await api.checkEmailAvailable(email);
emit(state.copyWith(emailError: isValid ? null : 'Email taken'));
},
);
void autoSave(String content) => mix(
key: AutoSave,
debounce: debounce(duration: 2.sec), // Save after 2 seconds of inactivity
() async {
await api.saveDraft(content);
emit(state.copyWith(lastSaved: DateTime.now()));
},
);
void search(String query) => mix(
key: this,
debounce: debounce(duration: 300.millis),
() async {
final results = await api.search(query);
emit(state.copyWith(results: results));
},
);
// In widget
Widget build(BuildContext context) {
return Column(
children: [
TextField(
onChanged: (value) => context.read<SearchCubit>().search(value),
),
if (context.isWaiting(SearchCubit))
const LinearProgressIndicator(),
// ... results list
],
);
}
| Feature | Behavior | Best For |
|---|---|---|
| Debounce | Executes after inactivity | Search, validation, auto-save |
| Throttle | Executes first call, ignores rest | Scroll, resize, refresh |
Debounce example: User types "hello"
Throttle example: User scrolls rapidly
class SearchCubit extends Cubit<SearchState> {
SearchCubit() : super(const SearchState());
void search(String query) => mix(
key: this,
debounce: debounce(duration: 300.millis),
() async {
if (query.trim().isEmpty) {
emit(state.copyWith(results: [], query: ''));
return;
}
final results = await api.search(query);
emit(state.copyWith(results: results, query: query));
},
);
void searchInCategory(String category, String query) => mix(
key: (Search, category), // State tracking per category
debounce: debounce(key: (Search, category)), // Debounce per category
() async {
final results = await api.searchInCategory(category, query);
emit(state.copyWith(
categoryResults: {...state.categoryResults, category: results},
));
},
);
}
// Widget
class SearchScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final state = context.watch<SearchCubit>().state;
return Column(
children: [
TextField(
decoration: const InputDecoration(hintText: 'Search...'),
onChanged: (value) => context.read<SearchCubit>().search(value),
),
if (context.isWaiting(SearchCubit))
const LinearProgressIndicator(),
Expanded(
child: ListView.builder(
itemCount: state.results.length,
itemBuilder: (context, index) => ListTile(
title: Text(state.results[index].title),
),
),
),
],
);
}
}
Ask the user: