بنقرة واحدة
convert-cubit
Convert an existing Cubit to use mix() function, removing manual loading and error state management
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Convert an existing Cubit to use mix() function, removing manual loading and error state management
التثبيت باستخدام 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 | convert-cubit |
| description | Convert an existing Cubit to use mix() function, removing manual loading and error state management |
This skill converts an existing Cubit to use the mix() function, removing manual loading/error state management.
mix()isLoading and errorMessage state managementUserExceptioncontext.isWaiting() and context.isFailed()Ask the user which Cubit they want to convert, or identify Cubits that have:
isLoading field in stateerrorMessage or error field in stateemit(state.copyWith(isLoading: true)) callsBefore (manual state management):
class UserCubit extends Cubit<UserState> {
UserCubit() : super(UserState());
Future<void> loadUser() async {
emit(state.copyWith(isLoading: true, errorMessage: null));
try {
final user = await api.getUser();
if (user == null) {
emit(state.copyWith(isLoading: false, errorMessage: 'Failed to load user'));
return;
}
emit(state.copyWith(user: user, isLoading: false));
} catch (e) {
emit(state.copyWith(isLoading: false, errorMessage: e.toString()));
}
}
}
After (with mix):
import 'package:bloc_superpowers/bloc_superpowers.dart';
class UserCubit extends Cubit<UserState> {
UserCubit() : super(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));
},
);
}
Before:
class UserState {
final User? user;
final bool isLoading;
final String? errorMessage;
UserState({
this.user,
this.isLoading = false,
this.errorMessage,
});
UserState copyWith({
User? user,
bool? isLoading,
String? errorMessage,
}) {
return UserState(
user: user ?? this.user,
isLoading: isLoading ?? this.isLoading,
errorMessage: errorMessage ?? this.errorMessage,
);
}
}
After:
class UserState {
final User? user;
const UserState({this.user});
UserState copyWith({User? user}) {
return UserState(user: user ?? this.user);
}
}
Before (reading state fields):
class UserWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final state = context.watch<UserCubit>().state;
if (state.isLoading) {
return const CircularProgressIndicator();
}
if (state.errorMessage != null) {
return Text('Error: ${state.errorMessage}');
}
return Text('Hello, ${state.user?.name}');
}
}
After (using context extensions):
class UserWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (context.isWaiting(UserCubit)) {
return const CircularProgressIndicator();
}
if (context.isFailed(UserCubit)) {
return Text('Error: ${context.getException(UserCubit)}');
}
final state = context.watch<UserCubit>().state;
return Text('Hello, ${state.user?.name}');
}
}
If a Cubit has multiple methods that need separate loading states, use different keys:
Option A: Same key for all methods (shared loading state)
class UserCubit extends Cubit<UserState> {
void loadUser() => mix(
key: this, // All methods share UserCubit key
() async { ... },
);
void updateUser(User user) => mix(
key: this, // Same key
() async { ... },
);
}
// Widget shows loading for ANY operation:
if (context.isWaiting(UserCubit)) { ... }
Option B: Different keys per method (separate loading states)
enum UserAction { load, update, delete }
class UserCubit extends Cubit<UserState> {
void loadUser() => mix(
key: UserAction.load,
() async { ... },
);
void updateUser(User user) => mix(
key: UserAction.update,
() async { ... },
);
}
// Widget can check specific operations:
if (context.isWaiting(UserAction.load)) { ... }
if (context.isWaiting(UserAction.update)) { ... }
For each Cubit being converted:
import 'package:bloc_superpowers/bloc_superpowers.dart';mix(key: this, () async { ... })emit(state.copyWith(isLoading: true)) callsemit(state.copyWith(isLoading: false)) callsthrow UserException('message')isLoading field from state classerrorMessage/error field from state classcopyWith to remove loading/error parametersstate.isLoading with context.isWaiting(CubitType)state.errorMessage with context.isFailed(CubitType) and context.getException(CubitType)Before:
if (user == null) {
emit(state.copyWith(isLoading: false, errorMessage: 'Not found'));
return;
}
After:
if (user == null) throw UserException('User not found');
Before:
try {
final data = await api.getData();
emit(state.copyWith(data: data, isLoading: false));
} catch (e) {
emit(state.copyWith(isLoading: false, errorMessage: e.toString()));
}
After:
mix(
key: this,
() async {
final data = await api.getData();
emit(state.copyWith(data: data));
},
);
// Errors automatically tracked; UserExceptionDialog shows them
Before:
try {
await api.saveUser(user);
} on NetworkException {
emit(state.copyWith(errorMessage: 'No internet connection'));
} on ValidationException catch (e) {
emit(state.copyWith(errorMessage: e.message));
} catch (e) {
emit(state.copyWith(errorMessage: 'Something went wrong'));
}
After:
mix(
key: this,
catchError: (error, stackTrace) {
if (error is NetworkException) {
throw UserException('No internet connection');
} else if (error is ValidationException) {
throw UserException(error.message);
} else {
throw UserException('Something went wrong');
}
},
() async {
await api.saveUser(user);
},
);