mcpField
B
bloc

bloc

github.com/verygoodopensource開発175102 回インストール3 日前に更新
リポジトリ

bloc について

Dart と Flutter アプリで Bloc 状態管理パターンを使うための開発・テスト用ワークフロースキルです。アーキテクチャ、イベントと状態、ウィジェット連携に加え、`bloc_test` と `mocktail` によるテストの規約を示します。

主な機能

  1. 01Bloc と Cubit の設計指針
  2. 02Page と View の分離
  3. 03イベントと状態の規約
  4. 04ウィジェット連携パターン
  5. 05`bloc_test` と `mocktail` によるテスト

活用シーン

  1. 01Bloc または Cubit でビジネスロジックを構成
  2. 02プレゼンテーション、ロジック、データ層を分離
  3. 03状態を Flutter ウィジェットに接続
  4. 04Bloc と Cubit のテストを作成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/verygoodopensource/vgv-ai-flutter-plugin --skill bloc

インストール後、Claude Code で/blocを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

agents/
openai.yaml
references/
architecture.md
patterns.md
testing.md
widgets.md

詳細

Bloc

BLoC(Business Logic Component)パターンを使用し、ビジネスロジックとプレゼンテーション層を分離する、Dart および Flutter 向けの状態管理ライブラリです。


コア標準

すべての Bloc/Cubit の作業に、以下の標準を適用してください。

  • すべての Bloc および Cubit のテストには package:bloc_test の blocTest() を使用してください — 手動でストリームをアサートする生の test() は使用しないでください
  • モックには package:mocktail を使用してください — package:mockito は使用しないでください
  • build: でテスト対象の Bloc を構築します — コールバックから新しいインスタンスを返してください。setUp で構築して共有してはいけません。これにより、各 blocTest はクリーンな Bloc から開始し、そのライフサイクルも blocTest によって管理されます
  • Bloc 間で直接依存しないでください — Bloc 同士は UI または共有リポジトリを通じて連携します
  • Page/View を分離します — Page は BlocProvider を通じて Bloc/Cubit を提供し、View は BlocBuilder/BlocListener を通じて利用します
  • イベントと複数の状態型には sealed クラスを使用します — Dart 3 の switch による網羅的なパターンマッチングが可能になります
  • すべての状態とイベントに Equatable を使用します — Equatable を継承し、値の等価性のために props をオーバーライドします
  • ビジネスロジックは Bloc/Cubit のみに記述します — ウィジェット、Page、View には記述しないでください
  • 単一責任を守ります — 機能ごとに Bloc/Cubit を 1 つ使用します
  • emit はハンドラー内でのみ呼び出します — on<Event> コールバックまたは Cubit メソッドから呼び出してください。ストリームサブスクリプションや、ハンドラーの終了後も存続するコールバックから呼び出してはいけません
  • Dart 3.13 のプライマリコンストラクター — Dart 3.13 以降をベースラインとする場合は、イベント、状態、ウィジェットのフィールドをプライマリコンストラクターの宣言パラメーターとして宣言してください(class const ProfileRequested(final String userId) extends ProfileEvent)。this.field を使う従来の形式は、3.13 未満の場合にのみ使用してください

Cubit と Bloc の比較

項目CubitBloc
API関数 → emit(state)イベント → on<Event> → emit(state)
複雑さ低い高い
追跡可能性低い(イベントログなし)完全(イベント+状態遷移)
用途シンプルな状態、UI 主導のロジック複雑なフロー、イベント駆動、変換
テストメソッドを呼び出し、状態をアサートイベントを追加し、状態をアサート
Cubit の例
class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);

  void increment() => emit(state + 1);
  void decrement() => emit(state - 1);
}
Bloc の例
sealed class CounterEvent extends Equatable {
  const CounterEvent();

  @override
  List<Object> get props => [];
}

final class CounterIncrementPressed extends CounterEvent {}
final class CounterDecrementPressed extends CounterEvent {}

class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0) {
    on<CounterIncrementPressed>((event, emit) => emit(state + 1));
    on<CounterDecrementPressed>((event, emit) => emit(state - 1));
  }
}

命名規則

イベント

パターン: BlocSubject + Noun + VerbPastTense

イベントクラス名意味
TodoListSubscriptionRequestedtodo リストのストリームを購読する
TodoListTodoDeleted特定の todo を削除する
TodoListUndoDeletionRequested直前の削除を取り消す
LoginFormSubmittedログインフォームを送信する
ProfilePageRefreshedプロフィールページを更新する
sealed class TodoListEvent extends Equatable {
  const TodoListEvent();

  @override
  List<Object> get props => [];
}

final class TodoListSubscriptionRequested extends TodoListEvent {}

final class const TodoListTodoDeleted({required final Todo todo})
    extends TodoListEvent {
  @override
  List<Object> get props => [todo];
}
状態
サブクラス方式(複数の状態型)

各状態が異なるデータを持つ場合に使用します。

状態クラス名意味
LoginInitialまだ何も実行されていない状態
LoginInProgressログインリクエスト実行中
LoginSuccessログイン成功
LoginFailureログイン失敗
sealed class LoginState extends Equatable {
  const LoginState();

  @override
  List<Object> get props => [];
}

final class LoginInitial extends LoginState {}
final class LoginInProgress extends LoginState {}
final class const LoginSuccess({required final User user}) extends LoginState {
  @override
  List<Object> get props => [user];
}
final class const LoginFailure({required final String error})
    extends LoginState {
  @override
  List<Object> get props => [error];
}
単一クラス方式(1 つの状態と複数のフィールド)

すべての状態でデータの形が共通する場合に使用します。status 列挙型とデータフィールドを持つ 1 つのクラスを用意し、状態遷移には copyWith を使用します。完全な構成については、references/patterns.md を参照してください。


アーキテクチャ

レイヤー含まれるもの依存先
プレゼンテーションページ、ビュー、ウィジェットビジネスロジック
ビジネスロジックBloc、Cubitデータ
データリポジトリ、データプロバイダー外部ソース
データレイヤー

リポジトリはデータソースを抽象化し、Bloc/Cubit にクリーンな API を提供します。すべてのテストファイルについて、test/ 内に機能フォルダー構造を再現してください。

リポジトリの例、機能フォルダー構造、テストディレクトリのレイアウトについては、references/architecture.md を参照してください。


Flutter ウィジェット

BlocProvider を使って Bloc または Cubit をサブツリーに提供し、BlocBuilder、 BlocListener、BlocConsumer、または BlocSelector で利用します。再ビルドを状態全体ではなく特定のフィールドに依存させたい場合は BlocSelector を、ナビゲーションやスナックバーなどの副作用には BlocListener を使用します。

重要なルールは次のとおりです。コールバック(onPressed、onTap)では context.read、build 内では context.watch または BlocBuilder を使います。build メソッドの外で context.watch を呼び出してはいけません。

追加リソース

  • references/architecture.md — リポジトリの例、機能フォルダー構造、テストディレクトリのレイアウト
  • references/widgets.md — ウィジェットと context 拡張の一覧、Page/View パターン、BlocListener の例
  • references/testing.md — blocTest() のパラメーター、Cubit/Bloc のテスト例、依存関係のモック、ウィジェット統合テスト
  • references/patterns.md — 単一クラスの状態、Bloc/Cubit を使った機能の追加、非同期処理、イベントトランスフォーマー

コメント