ワンクリックで
add-error-display
Add error state handling to widgets using context.isFailed() and context.getException()
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Add error state handling to widgets using context.isFailed() and context.getException()
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 freshness caching to prevent redundant method executions within a time period
| name | add-error-display |
| description | Add error state handling to widgets using context.isFailed() and context.getException() |
This skill adds error state handling to widgets using context.isFailed() and context.getException().
Shows error UI in widgets by:
context.isFailed(key) to check if an operation failedcontext.getException(key) to get the error messageThe Cubit method must use mix() with a key:
class UserCubit extends Cubit<User?> {
void loadUser() => mix(
key: this,
() async {
final user = await api.getUser();
if (user == null) throw UserException('User not found');
emit(user);
},
);
}
Check context.isFailed(key) in the widget's build method:
class UserScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Check if failed
if (context.isFailed(UserCubit)) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Error: ${context.getException(UserCubit)}'),
ElevatedButton(
onPressed: () => context.read<UserCubit>().loadUser(),
child: const Text('Retry'),
),
],
),
);
}
// Check if loading
if (context.isWaiting(UserCubit)) {
return const Center(child: CircularProgressIndicator());
}
// Show data
final user = context.watch<UserCubit>().state;
return Text('Hello, ${user?.name}');
}
}
| Extension | Returns | Description |
|---|---|---|
context.isFailed(key) | bool | True if operation threw an exception |
context.getException(key) | UserException? | The exception that was thrown |
context.clearException(key) | void | Manually clears the error state |
Widget build(BuildContext context) {
if (context.isFailed(UserCubit)) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, size: 64, color: Colors.red),
const SizedBox(height: 16),
Text(
'${context.getException(UserCubit)}',
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () => context.read<UserCubit>().loadUser(),
child: const Text('Try Again'),
),
],
),
),
);
}
// ...
}
Widget build(BuildContext context) {
return Column(
children: [
if (context.isFailed(UserCubit))
MaterialBanner(
content: Text('${context.getException(UserCubit)}'),
actions: [
TextButton(
onPressed: () => context.read<UserCubit>().loadUser(),
child: const Text('Retry'),
),
TextButton(
onPressed: () => context.clearException(UserCubit),
child: const Text('Dismiss'),
),
],
),
// Rest of content
UserContent(),
],
);
}
Show error but keep displaying old data:
Widget build(BuildContext context) {
final state = context.watch<ProductCubit>().state;
return Column(
children: [
// Show error banner if failed, but keep showing products
if (context.isFailed(ProductCubit))
Container(
color: Colors.red.shade100,
padding: const EdgeInsets.all(8),
child: Row(
children: [
Expanded(
child: Text('Failed to refresh: ${context.getException(ProductCubit)}'),
),
TextButton(
onPressed: () => context.read<ProductCubit>().loadProducts(),
child: const Text('Retry'),
),
],
),
),
// Show existing products even if refresh failed
Expanded(
child: ProductsList(products: state.products),
),
],
);
}
Widget build(BuildContext context) {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
final key = (DeleteItem, item.id);
// Check error for this specific item
if (context.isFailed(key)) {
return ListTile(
title: Text(item.name),
subtitle: Text(
'Delete failed: ${context.getException(key)}',
style: const TextStyle(color: Colors.red),
),
trailing: IconButton(
icon: const Icon(Icons.refresh),
onPressed: () => cubit.deleteItem(item.id),
),
);
}
return ListTile(
title: Text(item.name),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () => cubit.deleteItem(item.id),
),
);
},
);
}
Widget build(BuildContext context) {
return Form(
child: Column(
children: [
// Form fields
TextFormField(...),
TextFormField(...),
// Error message
if (context.isFailed(SubmitForm))
Padding(
padding: const EdgeInsets.all(8),
child: Text(
'${context.getException(SubmitForm)}',
style: const TextStyle(color: Colors.red),
),
),
// Submit button
ElevatedButton(
onPressed: context.isWaiting(SubmitForm)
? null
: () => context.read<FormCubit>().submit(formData),
child: context.isWaiting(SubmitForm)
? const CircularProgressIndicator()
: const Text('Submit'),
),
],
),
);
}
Errors are automatically cleared when:
context.clearException(key)// Error cleared when loadUser() is called again
context.read<UserCubit>().loadUser();
// Manually clear error
context.clearException(UserCubit);
class DataScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Data')),
body: _buildBody(context),
);
}
Widget _buildBody(BuildContext context) {
// Error state - full screen
if (context.isFailed(DataCubit)) {
return _buildErrorView(context);
}
// Loading state
if (context.isWaiting(DataCubit)) {
return const Center(child: CircularProgressIndicator());
}
// Success state
final data = context.watch<DataCubit>().state;
return _buildDataView(context, data);
}
Widget _buildErrorView(BuildContext context) {
return Center(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.cloud_off,
size: 64,
color: Colors.grey,
),
const SizedBox(height: 16),
Text(
'${context.getException(DataCubit)}',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 24),
ElevatedButton.icon(
onPressed: () => context.read<DataCubit>().loadData(),
icon: const Icon(Icons.refresh),
label: const Text('Try Again'),
),
],
),
),
);
}
Widget _buildDataView(BuildContext context, DataState data) {
return RefreshIndicator(
onRefresh: () async {
context.read<DataCubit>().loadData();
},
child: ListView.builder(
itemCount: data.items.length,
itemBuilder: (context, index) => ListTile(
title: Text(data.items[index].name),
),
),
);
}
}
Ask the user: