一键导入
add-non-reentrant
Add non-reentrant protection to prevent a Cubit method from running multiple times simultaneously
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Add non-reentrant protection to prevent a Cubit method from running multiple times simultaneously
用 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 debounce to delay method execution until after a period of inactivity for search or validation
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()
| name | add-non-reentrant |
| description | Add non-reentrant protection to prevent a Cubit method from running multiple times simultaneously |
This skill prevents a Cubit method from running multiple times simultaneously.
Adds the nonReentrant parameter to a mix() call so that:
This is equivalent to droppable() from the bloc_concurrency package, but for Cubit methods.
Ask the user which Cubit method needs non-reentrant protection, or identify methods that:
Add nonReentrant: nonReentrant to the mix() call:
import 'package:bloc_superpowers/bloc_superpowers.dart';
class UserCubit extends Cubit<User> {
UserCubit() : super(User());
void loadData() => mix(
key: this,
nonReentrant: nonReentrant, // Add this line
() async {
final user = await api.loadUser();
emit(user);
},
);
}
With nonReentrant:
// User taps "Load" button rapidly 3 times
cubit.loadData(); // ✓ Executes
cubit.loadData(); // ✗ Ignored (first still running)
cubit.loadData(); // ✗ Ignored (first still running)
// First call completes
cubit.loadData(); // ✓ Executes (previous call finished)
Prevent duplicate API calls:
void loadProducts() => mix(
key: this,
nonReentrant: nonReentrant,
() async {
final products = await api.getProducts();
emit(state.copyWith(products: products));
},
);
Combine for robust data loading:
void loadData() => mix(
key: this,
nonReentrant: nonReentrant,
retry: retry,
() async {
final data = await api.getData();
emit(data);
},
);
Prevent double-submit:
void submitForm(FormData data) => mix(
key: this,
nonReentrant: nonReentrant,
() async {
await api.submit(data);
emit(state.copyWith(submitted: true));
},
);
Allow concurrent operations for different items, but prevent duplicate operations on the same item:
void processItem(String itemId) => mix(
key: this,
nonReentrant: nonReentrant(key: (ProcessItem, itemId)),
() async {
await api.processItem(itemId);
},
);
With this setup:
processItem('A') and processItem('B') can run concurrentlyprocessItem('A') called twice rapidly: second call is ignoredvoid deleteItem(String id) => mix(
key: (DeleteItem, id), // State tracking per item
nonReentrant: nonReentrant, // Inherits key from mix
() async {
await api.deleteItem(id);
emit(state.copyWith(
items: state.items.where((i) => i.id != id).toList(),
));
},
);
| Feature | Behavior |
|---|---|
nonReentrant | Drops duplicate calls while running |
sequential | Queues calls and processes one at a time |
Use nonReentrant when:
Use sequential when:
Good candidates:
Not recommended:
sequential instead)class ProductCubit extends Cubit<ProductState> {
ProductCubit() : super(const ProductState());
// Prevent duplicate loads
void loadProducts() => mix(
key: this,
nonReentrant: nonReentrant,
retry: retry,
() async {
final products = await api.getProducts();
emit(state.copyWith(products: products));
},
);
// Prevent double-delete on same item
void deleteProduct(String id) => mix(
key: (DeleteProduct, id),
nonReentrant: nonReentrant,
() async {
await api.deleteProduct(id);
emit(state.copyWith(
products: state.products.where((p) => p.id != id).toList(),
));
},
);
// Prevent double-submit
void checkout() => mix(
key: Checkout,
nonReentrant: nonReentrant,
() async {
final order = await api.checkout(state.cart);
emit(state.copyWith(order: order, cart: []));
},
);
}