dart-flutter-patterns
Official生产就绪的 Dart 和 Flutter 模式,涵盖空安全、不可变状态、异步组合、Widget 架构、流行的状态管理框架(BLoC、Riverpod、Provider)、GoRouter 导航、Dio 网络请求、Freezed 代码生成和整洁架构。
What this skill does
When applied, it prepends a system prompt before your request is sent — no extra calls and no change to how you are billed beyond the added tokens.
---
name: dart-flutter-patterns
description: 生产就绪的 Dart 和 Flutter 模式,涵盖空安全、不可变状态、异步组合、Widget 架构、流行的状态管理框架(BLoC、Riverpod、Provider)、GoRouter 导航、Dio 网络请求、Freezed 代码生成和整洁架构。
origin: ECC
---
# Dart/Flutter 模式
## 使用场景
在以下情况使用此技能:
* 开始新的 Flutter 功能,需要状态管理、导航或数据访问的惯用模式
* 审查或编写 Dart 代码,需要空安全、密封类型或异步组合的指导
* 搭建新的 Flutter 项目,在 BLoC、Riverpod 或 Provider 之间做选择
* 实现安全的 HTTP 客户端、WebView 集成或本地存储
* 为 Flutter 组件、Cubit 或 Riverpod 提供者编写测试
* 使用认证守卫配置 GoRouter
## 工作原理
此技能提供按关注点组织的、可直接复制粘贴的 Dart/Flutter 代码模式:
1. **空安全** — 避免 `!`,优先使用 `?.`/`??`/模式匹配
2. **不可变状态** — 密封类、`freezed`、`copyWith`
3. **异步组合** — 并发 `Future.wait`、`BuildContext` 后安全使用 `await`
4. **组件架构** — 提取为类(而非方法)、`const` 传播、作用域重建
5. **状态管理** — BLoC/Cubit 事件、Riverpod 通知器和派生提供者
6. **导航** — 通过 `refreshListenable` 实现带响应式认证守卫的 GoRouter
7. **网络请求** — 带拦截器的 Dio、带一次性重试守卫的令牌刷新
8. **错误处理** — 全局捕获、`ErrorWidget.builder`、Crashlytics 集成
9. **测试** — 单元测试(BLoC 测试)、组件测试(ProviderScope 覆盖)、使用假对象而非模拟对象
## 示例
```dart
// Sealed state — prevents impossible states
sealed class AsyncState<T> {}
final class Loading<T> extends AsyncState<T> {}
final class Success<T> extends AsyncState<T> { final T data; const Success(this.data); }
final class Failure<T> extends AsyncState<T> { final Object error; const Failure(this.error); }
// GoRouter with reactive auth redirect
final router = GoRouter(
refreshListenable: GoRouterRefreshStream(authCubit.stream),
redirect: (context, state) {
final authed = context.read<AuthCubit>().state is AuthAuthenticated;
if (!authed && !state.matchedLocation.startsWith('/login')) return '/login';
return null;
},
routes: [...],
);
// Riverpod derived provider with safe firstWhereOrNull
@riverpod
double cartTotal(Ref ref) {
final cart = ref.watch(cartNotifierProvider);
final products = ref.watch(productsProvider).valueOrNull ?? [];
return cart.fold(0.0, (total, item) {
final product = products.firstWhereOrNull((p) => p.id == item.productId);
return total + (product?.price ?? 0) * item.quantity;Use this skill
Add a "skill" field with the skill’s ID to your chat completion request. It is applied server-side before your prompt is sent — no extra calls.
{
"model": "gpt-4o-mini",
"skill": "imp-1f5a3d38-cde3-48f7-9484-d5a1c53d9a5e",
"messages": [{ "role": "user", "content": "…" }]
}Install the skill, enable it in your dashboard and (optionally) limit it to specific models. It then applies automatically to every matching request — with no "skill" field to send each time.
Set it up in your dashboardMore skills
Delegate coding work to Codex, Claude Code, or OpenCode as background workers; not simple edits or read-only code lookup.
Create, edit, audit, tidy, validate, or restructure AgentSkills and SKILL.md files.
Search and analyze your own session logs (older/parent conversations) using jq.
Create, view, edit, delete, search, move, or export Apple Notes via the memo CLI on macOS.
Diagnose OpenClaw Android, iOS, or macOS node pairing, QR/setup code, route, auth, and connection failures.
Set up and use 1Password CLI for sign-in, desktop integration, and reading or injecting secrets.
List, add, edit, complete, or delete Apple Reminders and reminder lists via remindctl.
Create, search, and manage Bear notes via grizzly CLI.