state-management
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseBLoC Pattern
BLoC 模式
- Sealed States & Events: Always use for both States and Events to ensure exhaustive UI handling and compile-time safety.
sealed class - Immutability: All States, Events, and Domain Entities MUST be immutable (using and
finalorEquatable).freezed - Official BLoC Part-Part Of Pattern: Every file MUST include its corresponding
_bloc.dartand_event.dartfiles using_state.dartdirectives. Each event/state file MUST have apartdirective pointing back to the bloc file. This ensures a single library scope and shared private members.part ofdart// 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'; - Mandatory Directory Structure: Every BLoC feature set MUST reside in its own sub-directory within the folder. Flat
bloc/directories are STRICTLY prohibited.bloc/textpresentation/bloc/ └── <bloc_name>/ ├── <bloc_name>_bloc.dart ├── <bloc_name>_event.dart └── <bloc_name>_state.dart - Loading State Mandate: ALWAYS emit before async work, then
LoadingorSuccess. Never skip the loading state.Error - Concurrency: Use (e.g.,
transformers,restartable()) for events requiring debouncing (search) or throttling (buttons).droppable() - Zero-Logic UI: Widgets MUST NOT contain business logic, orchestration logic, or direct calls to external services. They should ONLY dispatch events and build UI based on BLoC states.
- 密封状态与事件:始终对状态和事件使用 ,以确保全面的UI处理和编译时安全性。
sealed class - 不可变性:所有状态、事件和领域实体必须是不可变的(使用 以及
final或Equatable实现)。freezed - 官方 BLoC Part-Part Of 模式:每个 文件必须使用
_bloc.dart指令引入对应的part和_event.dart文件。每个事件/状态文件必须包含指向对应bloc文件的_state.dart指令。这能保证单一库作用域以及私有成员的共享。part ofdart// 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/textpresentation/bloc/ └── <bloc_name>/ ├── <bloc_name>_bloc.dart ├── <bloc_name>_event.dart └── <bloc_name>_state.dart - 加载状态要求:在执行异步操作前始终抛出 状态,之后再抛出
Loading或Success状态。绝对不能跳过加载状态。Error - 并发处理:对需要防抖(搜索)或节流(按钮点击)的事件使用 (例如
transformers、restartable())。droppable() - UI零逻辑:Widgets 绝对不能包含业务逻辑、编排逻辑或者直接调用外部服务。它们只应该派发事件,并根据BLoC的状态构建UI。
BLoC Widget Usage
BLoC Widget 使用规范
- for local UI rebuilds based on state
BlocBuilder - for side effects (navigation, snackbars, dialogs)
BlocListener - when both rebuild and side effects are needed
BlocConsumer - for dispatching events
context.read<Bloc>().add(Event()) - for reactive rebuilds (inside
context.watch<Bloc>().stateonly)build()
- 使用 基于状态实现局部UI重绘
BlocBuilder - 使用 处理副作用(导航、snackbars、弹窗)
BlocListener - 同时需要重绘和副作用时使用
BlocConsumer - 使用 派发事件
context.read<Bloc>().add(Event()) - 仅在 方法内使用
build()实现响应式重绘context.watch<Bloc>().state
BLoC Submission Checklist
BLoC 提交检查清单
- Events and States use with correct
Equatableprops - All async operations follow pattern
Loading → Success/Error - No business logic in UI widgets
- No SDK/API calls outside DataSources
- Zero hardcoded colors, spacing, or typography \u2014 use design tokens (,
AppColors)AppSpacing - Code formatted with
dart format
- 事件和状态使用 并配置了正确的
Equatableprops - 所有异步操作都遵循 模式
Loading → Success/Error - UI Widget 中没有业务逻辑
- 没有在 DataSources 之外调用SDK/API
- 没有硬编码的颜色、间距或排版——使用设计令牌(、
AppColors)AppSpacing - 代码已经使用 格式化
dart format
Dependency Injection
依赖注入
- Use for dependency injection and service location
injectable - Standardized Injection:
- Use for screen-specific BLoCs to ensure a fresh instance per screen access.
@injectable - Use for global or shared BLoCs (e.g.,
@lazySingleton,AuthBloc,ThemeBloc,SettingsBloc).PasswordBloc
- Use
- Organize blocs logically by feature and ensure strict separation of concerns
- 使用 实现依赖注入和服务定位
injectable - 标准化注入规则:
- 对页面专属的BLoC使用 ,确保每次访问页面时都得到全新的实例
@injectable - 对全局或共享的BLoC使用 (例如
@lazySingleton、AuthBloc、ThemeBloc、SettingsBloc)PasswordBloc
- 对页面专属的BLoC使用
- 按功能逻辑组织BLoC,确保严格的关注点分离
Navigation & Routing
导航与路由
- Dynamic Routes: STRICTLY prohibit hardcoded route strings in configuration. Use static constants in
GoRouter.AppRoutes - Centralized BLoCs: BLoC providers MUST be injected via or
ShellRouteinBlocProviderwhen shared across multiple screens or within a feature branch.app_router.dart - No Local Providers: Avoid in individual screen
BlocProvidermethods if the BLoC is needed by a feature set.build() - Primitive Route Arguments: STRICTLY prohibit passing complex objects (BLoCs, ChangeNotifiers, Entity instances) as route arguments. Pass only primitive IDs/Keys and fetch data in the destination screen using or
Repositoryinjection.Bloc
- 动态路由:严格禁止在 配置中硬编码路由字符串。请使用
GoRouter中的静态常量。AppRoutes - 集中式BLoC注入:如果BLoC需要在多个页面或某个功能分支内共享,必须通过 中的
app_router.dart或ShellRoute进行注入。BlocProvider - 禁止局部Provider:如果某个BLoC是整个功能集所需,不要在单个页面的 方法中使用
build()注入。BlocProvider - 基础类型路由参数:严格禁止传递复杂对象(BLoC、ChangeNotifier、实体实例)作为路由参数。仅传递基础类型的ID/键,在目标页面通过注入的 或
Repository获取数据。Bloc