用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin --skill bloc命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | bloc |
| description | Best practices for Bloc state management in Flutter/Dart. |
| when_to_use | Use when writing, modifying, or reviewing code that uses package:bloc, package:flutter_bloc, or package:bloc_test. |
| allowed-tools | Read Glob Grep |
State management library for Dart and Flutter using the BLoC (Business Logic Component) pattern to separate business logic from the presentation layer.
Apply these standards to ALL Bloc/Cubit work:
blocTest() from package:bloc_test for all Bloc and Cubit tests — never raw test() with manual stream assertionspackage:mocktail for mocking — never package:mockitoBlocProvider, View consumes via BlocBuilder/BlocListenerswitchEquatable and override props for value equalityemit only inside the handler callback| Aspect | Cubit | Bloc |
|---|---|---|
| API | Functions → emit(state) | Events → on<Event> → emit(state) |
| Complexity | Low | Higher |
| Traceability | Less (no event log) | Full (events + transitions) |
| When to use | Simple state, UI-driven logic | Complex flows, event-driven, transforms |
| Testing | Call methods, assert states | Add events, assert states |
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
}
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));
}
}
Pattern: BlocSubject + Noun + VerbPastTense
| Event class name | Meaning |
|---|---|
TodoListSubscriptionRequested | Subscribing to todo list stream |
TodoListTodoDeleted | Deleting a specific todo |
TodoListUndoDeletionRequested | Undoing the last deletion |
LoginFormSubmitted | Submitting the login form |
ProfilePageRefreshed | Refreshing the profile page |
sealed class TodoListEvent extends Equatable {
const TodoListEvent();
@override
List<Object> get props => [];
}
final class TodoListSubscriptionRequested extends TodoListEvent {}
final class TodoListTodoDeleted extends TodoListEvent {
const TodoListTodoDeleted({required this.todo});
final Todo todo;
@override
List<Object> get props => [todo];
}
Use when each state carries different data.
| State class name | Meaning |
|---|---|
LoginInitial | No action taken yet |
LoginInProgress | Login request in flight |
LoginSuccess | Login succeeded |
LoginFailure | Login failed |
sealed class LoginState extends Equatable {
const LoginState();
@override
List<Object> get props => [];
}
final class LoginInitial extends LoginState {}
final class LoginInProgress extends LoginState {}
final class LoginSuccess extends LoginState {
const LoginSuccess({required this.user});
final User user;
@override
List<Object> get props => [user];
}
final class LoginFailure extends LoginState {
const LoginFailure({required this.error});
final String error;
@override
List<Object> get props => [error];
}
Use when all states share the same data shape.
| Field | Type | Purpose |
|---|---|---|
status | enum | Current loading status |
items | List<Item> | Loaded data |
error | String? | Error message if failed |
enum TodoListStatus { initial, loading, success, failure }
class TodoListState extends Equatable {
const TodoListState({
this.status = TodoListStatus.initial,
this.todos = const [],
this.error,
});
final TodoListStatus status;
final List<Todo> todos;
final String? error;
TodoListState copyWith({
TodoListStatus? status,
List<Todo>? todos,
String? error,
}) {
return TodoListState(
status: status ?? this.status,
todos: todos ?? this.todos,
error: error ?? this.error,
);
}
@override
List<Object?> get props => [status, todos, error];
}
| Layer | Contains | Depends on |
|---|---|---|
| Presentation | Pages, Views, Widgets | Business Logic |
| Business Logic | Blocs, Cubits | Data |
| Data | Repositories, Data Providers | External sources |
Repositories abstract data sources and provide a clean API for Blocs/Cubits. Mirror the feature folder structure under test/ for all test files.
See references/architecture.md for the repository example, feature folder structure, and test directory layout.
BlocProvider — creates and provides a Bloc/Cubit to the subtreeBlocBuilder — rebuilds widget when state changesBlocListener — executes side effects (navigation, snackbar) on state changeBlocConsumer — combines BlocBuilder + BlocListenerBlocSelector — rebuilds only when a selected property changescontext.read in callbacks (onPressed, onTap), context.watch or BlocBuilder in build methodscontext.watch outside of buildSee references/widgets.md for the full widget and context extension tables, Page/View pattern example, and BlocListener example. See references/testing.md for blocTest() parameters, Cubit/Bloc test examples, mocking dependencies, and widget integration tests. See references/patterns.md for adding features with Bloc/Cubit, async operations, and event transformers.
基于 SOC 职业分类