SuperAPI AI 工具集

vgv-bloc

编程与开发

查看项目

更新于 10-16 04:26

技能介绍

用途

vgv-bloc 是 verygoodopensource/vgv-ai-flutter-plugin 提供的一项技能,主题为 Flutter/Dart 中 Bloc 状态管理的最佳实践。Bloc 是 Dart 与 Flutter 的状态管理库,采用 BLoC(Business Logic Component)模式,将业务逻辑与展示层分离。该技能用于在编写 Bloc/Cubit 相关代码时遵循统一的标准与约定。

核心标准

以下标准适用于所有 Bloc/Cubit 工作:

  • 所有 Bloc 与 Cubit 测试使用 package:bloc_test 的 blocTest(),不要使用原始 test() 加手动流断言。
  • 使用 package:mocktail 进行 mock,不要使用 package:mockito。
  • 不允许 bloc 与 bloc 之间直接依赖,bloc 之间通过 UI 或共享 repository 通信。
  • Page/View 分离:Page 通过 BlocProvider 提供 Bloc/Cubit,View 通过 BlocBuilder/BlocListener 消费。
  • 事件与多状态类型使用 sealed class,以便配合 Dart 3 switch 进行穷尽模式匹配。
  • 所有状态与事件使用 Equatable,继承 Equatable 并重写 props 以实现值相等。
  • 业务逻辑只放在 Bloc/Cubit 中,不要放在 widget、page 或 view 中。
  • 单一职责:每个功能关注点对应一个 Bloc/Cubit。
  • 仅在异步检查之后 emit:只在 handler 回调内部使用 emit。

Cubit 与 Bloc 的对比

方面 Cubit Bloc
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。

事件类名 含义
TodoListSubscriptionRequested 订阅 todo 列表流
TodoListTodoDeleted 删除特定 todo
TodoListUndoDeletionRequested 撤销上一次删除
LoginFormSubmitted 提交登录表单
ProfilePageRefreshed 刷新个人资料页
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];
}

状态

子类方式(多种状态类型)

当每种状态携带不同数据时使用。

状态类名 含义
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 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];
}

单类方式(一个状态,多个字段)

当所有状态共享相同数据形状时使用。

字段 类型 用途
status enum 当前加载状态
items List<Item> 已加载数据
error String? 失败时的错误信息
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];
}

架构

层 包含 依赖
Presentation Pages、Views、Widgets Business Logic
Business Logic Blocs、Cubits Data
Data Repositories、Data Providers 外部来源

数据层

Repository 抽象数据源,为 Bloc/Cubit 提供干净的 API。所有测试文件在 test/ 下镜像功能文件夹结构。

关于 repository 示例、功能文件夹结构与测试目录布局,参见 references/architecture.md。

Flutter Widgets

  • BlocProvider — 创建并向子树提供 Bloc/Cubit
  • BlocBuilder — 状态变化时重建 widget
  • BlocListener — 状态变化时执行副作用(导航、snackbar)
  • BlocConsumer — 组合 BlocBuilder + BlocListener
  • BlocSelector — 仅在选定属性变化时重建

在回调(onPressed、onTap)中使用 context.read,在 build 方法中使用 context.watch 或 BlocBuilder。不要在 build 之外使用 context.watch。

关于完整的 widget 与 context 扩展表、Page/View 模式示例与 BlocListener 示例,参见 references/widgets.md。关于 blocTest() 参数、Cubit/Bloc 测试示例、mock 依赖与 widget 集成测试,参见 references/testing.md。关于使用 Bloc/Cubit 添加功能、异步操作与事件转换器,参见 references/patterns.md。

适用场景与限制

该技能适用于使用 Bloc/Cubit 进行状态管理的 Flutter/Dart 项目,尤其是需要统一事件与状态命名、分层架构和测试方式的团队。资料未提供具体的安装命令、版本要求、收费信息或平台限制。