بنقرة واحدة
create-cubit
Create a new Cubit using mix() function for automatic loading and error state tracking
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Create a new Cubit using mix() function for automatic loading and error state tracking
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | create-cubit |
| description | Create a new Cubit using mix() function for automatic loading and error state tracking |
This skill creates a new Cubit that uses the mix() function for automatic loading/error
state tracking.
Creates a Cubit class that:
mix() function to wrap async operationsisLoading field needed)errorMessage field needed)UserException for user-facing errorsAsk the user:
UserCubit, ProductCubit)User, List<Product>, or a
custom state class)loadData, save,
delete)Create a Cubit that uses mix() with key: this:
import 'package:bloc_superpowers/bloc_superpowers.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class UserCubit extends Cubit<User?> {
UserCubit() : super(null);
void loadUser() => mix(
key: this,
() async {
final user = await api.getUser();
if (user == null) throw UserException('Failed to load user');
emit(user);
},
);
}
For simple state (single value), use the value type directly:
class UserCubit extends Cubit<User?> { ... }
For complex state with multiple fields, create a state class without isLoading or
errorMessage:
class UserState {
final User? user;
final List<Post> posts;
const UserState({this.user, this.posts = const []});
UserState copyWith({User? user, List<Post>? posts}) {
return UserState(
user: user ?? this.user,
posts: posts ?? this.posts,
);
}
}
class UserCubit extends Cubit<UserState> {
UserCubit() : super(const UserState());
void loadUser() => mix(
key: this,
() async {
final user = await api.getUser();
if (user == null) throw UserException('Failed to load user');
emit(state.copyWith(user: user));
},
);
void loadPosts() => mix(
key: this,
() async {
final posts = await api.getPosts();
emit(state.copyWith(posts: posts));
},
);
}
Show loading and error states using context extensions:
class UserWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Show loading indicator while loading
if (context.isWaiting(UserCubit)) {
return const CircularProgressIndicator();
}
// Show error message if failed
if (context.isFailed(UserCubit)) {
return Text('Error: ${context.getException(UserCubit)}');
}
// Show the data
final user = context.watch<UserCubit>().state;
return Text('Hello, ${user?.name ?? "Guest"}');
}
}
The mix() function supports multiple declaration patterns:
// Arrow function with void return (most common)
void loadUser() => mix(
key: this,
() async { ... },
);
// Arrow function with Future return (when caller needs to await)
Future<void> loadUser() => mix(
key: this,
() async { ... },
);
// Block syntax (when you need additional logic before/after mix)
void loadUser() {
mix(
key: this,
() async { ... },
);
}
The mix() function accepts optional parameters for enhanced behavior:
| Parameter | Purpose |
|---|---|
retry | Automatically retry failed operations with backoff |
nonReentrant | Prevent concurrent executions of the same operation |
checkInternet | Verify connectivity before executing |
fresh | Cache freshness to skip redundant calls |
debounce | Delay execution to prevent rapid calls |
throttle | Limit execution frequency |
sequential | Execute operations in order |
catchError | Custom error handling |
config | Reusable configuration bundle |
Each parameter has a dedicated skill for detailed usage.
key: thisWhen you use key: this inside a Cubit method, it becomes the Cubit's runtimeType
(e.g., UserCubit), not the instance. This means:
context.isWaiting(UserCubit)For methods with parameters where you need separate loading states per item:
void loadUser(String userId) => mix(
key: (UserCubit, userId), // Composite key using a record
() async {
final user = await api.getUser(userId);
emit(state.copyWith(users: {...state.users, userId: user}));
},
);
// In widget:
if (context.isWaiting((UserCubit, userId))) { ... }
When something goes wrong, throw UserException with a user-friendly message:
void loadUser() => mix(
key: this,
() async {
final user = await api.getUser();
if (user == null) {
throw UserException('Could not load your profile. Please try again.');
}
emit(user);
},
);
import 'package:bloc_superpowers/bloc_superpowers.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
// State class (no isLoading or errorMessage!)
class TodoState {
final List<Todo> todos;
const TodoState({this.todos = const []});
TodoState copyWith({List<Todo>? todos}) {
return TodoState(todos: todos ?? this.todos);
}
}
// Cubit with mix()
class TodoCubit extends Cubit<TodoState> {
TodoCubit() : super(const TodoState());
void loadTodos() => mix(
key: this,
() async {
final todos = await api.getTodos();
emit(state.copyWith(todos: todos));
},
);
void addTodo(String title) => mix(
key: this,
() async {
final newTodo = await api.createTodo(title);
emit(state.copyWith(todos: [...state.todos, newTodo]));
},
);
void deleteTodo(String id) => mix(
key: (TodoCubit, 'delete', id), // Separate key per delete operation
() async {
await api.deleteTodo(id);
emit(state.copyWith(
todos: state.todos.where((t) => t.id != id).toList(),
));
},
);
}
// Widget
class TodoScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (context.isWaiting(TodoCubit)) {
return const Center(child: CircularProgressIndicator());
}
if (context.isFailed(TodoCubit)) {
return Center(
child: Column(
children: [
Text('Error: ${context.getException(TodoCubit)}'),
ElevatedButton(
onPressed: () => context.read<TodoCubit>().loadTodos(),
child: const Text('Retry'),
),
],
),
);
}
final todos = context.watch<TodoCubit>().state.todos;
return ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) => TodoTile(todo: todos[index]),
);
}
}
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()