flutter-bloc について
Flutter で状態管理を実装する開発者向けの BLoC スキルです。不変のイベントと状態、非同期処理、UI の責務、依存性注入、ルーティングの規約を定めています。
主な機能
- 01sealed な不変イベントと状態
- 02読み込みから結果への非同期フロー
- 03BLoC ウィジェットの使用指針
- 04依存性注入の規約
- 05ルーティングと Provider の規則
- 06機能ごとのディレクトリ構成
活用シーン
- 01Flutter BLoC 機能の実装開始
- 02非同期状態遷移の確認
- 03UI とビジネスロジックの分離
- 04ルーティングと BLoC Provider の整理
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ dhruvanbhalara/ skills --skill flutter-blocインストール後、Claude Code で/flutter-blocを入力して読み込まれたか確認します。
詳細
BLoC パターン
- シールドされた State と Event: State と Event の両方に常に
sealed classを使用し、UI の網羅的な処理とコンパイル時の安全性を確保します。 - 不変性: すべての State、Event、ドメインエンティティは不変でなければなりません(
finalとEquatableまたはfreezedを使用)。 - 公式 BLoC の Part-Part Of パターン: すべての
_bloc.dartファイルは、対応する_event.dartと_state.dartファイルをpartディレクティブで必ず含める必要があります。各 event/state ファイルには、bloc ファイルを指し示すpart ofディレクティブが必ず必要です。これにより、単一のライブラリスコープと共有されたプライベートメンバーが保証されます。// auth_bloc.dart part 'auth_event.dart'; part 'auth_state.dart'; class AuthBloc extends Bloc<AuthEvent, AuthState> { ... } // auth_event.dart part of 'auth_bloc.dart'; // auth_state.dart part of 'auth_bloc.dart'; - 必須のディレクトリ構造: すべての BLoC 機能セットは、
bloc/フォルダー内の独自のサブディレクトリに必ず配置する必要があります。フラットなbloc/ディレクトリは厳格に禁止します。presentation/bloc/ └── <bloc_name>/ ├── <bloc_name>_bloc.dart ├── <bloc_name>_event.dart └── <bloc_name>_state.dart - ローディング State の義務: 非同期処理の前に必ず
Loadingを emit し、その後SuccessまたはErrorを emit してください。ローディング State を決して省略しないでください。 - 並行処理: デバウンス(検索)やスロットリング(ボタン)が必要なイベントには、
transformers(例:restartable()、droppable())を使用します。 - ゼロロジック UI: ウィジェットにビジネスロジック、オーケストレーションロジック、外部サービスへの直接呼び出しを含めてはなりません。イベントを dispatch し、BLoC の State に基づいて UI を構築するだけにしてください。
BLoC ウィジェットの使用方法
- State に基づくローカルな UI 再構築には
BlocBuilder - 副作用(ナビゲーション、スナックバー、ダイアログ)には
BlocListener - 再構築と副作用の両方が必要な場合は
BlocConsumer - イベントの dispatch には
context.read<Bloc>().add(Event()) - リアクティブな再構築には
context.watch<Bloc>().state(build()内のみ)
ワークフロー: State 管理の実装
BLoC を追加または更新する際は、以下の順序でワークフローに従ってください。チェックリストをコピーして進捗を追跡してください。
タスクの進捗
- ステップ 1: Event と State を定義する。 正しい
propsを持つEquatableまたはfreezedを使用していることを確認してください。 - ステップ 2: 非同期操作を実装する。 すべての非同期処理が
Loading → Success/Errorパターンに従っていることを確認してください。 - ステップ 3: UI をリファクタリングする。 UI ウィジェットにオーケストレーションやビジネスロジックが存在しないことを確認してください。ウィジェットはイベントを dispatch するだけにしてください。
- ステップ 4: データソースを検証する。 DataSources の外に SDK/API 呼び出しが存在しないことを確認してください。
- ステップ 5: デザイントークンをレビューする。 ハードコードされた色、スペーシング、タイポグラフィが一切使用されていないことを確認してください。
- ステップ 6: コードをフォーマットする。 コードが
dart formatでフォーマットされていることを確認してください。
依存性注入
- 依存性注入とサービスロケーターには
injectableを使用します - 標準化された注入:
- 画面ごとに新しいインスタンスを保証するため、画面固有の BLoC には
@injectableを使用します。 - グローバルまたは共有の BLoC(例:
AuthBloc、ThemeBloc、SettingsBloc、PasswordBloc)には@lazySingletonを使用します。
- 画面ごとに新しいインスタンスを保証するため、画面固有の BLoC には
- BLoC を機能ごとに論理的に整理し、関心の厳格な分離を確保します
ナビゲーションとルーティング
- 動的ルート:
GoRouterの設定でハードコードされたルート文字列を厳格に禁止します。AppRoutesの静的定数を使用してください。 - 集中化された BLoC: 複数の画面で共有される場合、または機能ブランチ内で共有される場合、BLoC プロバイダーは
app_router.dartのShellRouteまたはBlocProviderを介して注入する必要があります。 - ローカルプロバイダーの禁止: BLoC が機能セットで必要とされる場合、個々の画面の
build()メソッドでBlocProviderを使用することは避けてください。 - プリミティブなルート引数: 複雑なオブジェクト(BLoC、ChangeNotifier、エンティティインスタンス)をルート引数として渡すことを厳格に禁止します。プリミティブな ID/Key のみを渡し、
RepositoryまたはBlocの注入を使用して遷移先の画面でデータを取得してください。
コメント
Markdown 対応