Files

65 lines
2.4 KiB
Cheetah

---
description: "BLoC / Cubit conventions for {{PROJECT_NAME}}"
alwaysApply: true
---
# BLoC / Cubit Standards — {{PROJECT_NAME}}
## When to use BLoC vs Cubit
- **Cubit**: simple state with no meaningful event history (toggle, counter, pagination)
- **BLoC**: event-driven flows where event history or transitions matter (auth, checkout, form wizard)
## Event and State classes
```dart
// Events — sealed class (exhaustive switch)
sealed class AuthEvent { const AuthEvent(); }
final class AuthLoginRequested extends AuthEvent {
final String email, password;
const AuthLoginRequested({required this.email, required this.password});
}
final class AuthLogoutRequested extends AuthEvent { const AuthLogoutRequested(); }
// States — sealed class, immutable
sealed class AuthState { const AuthState(); }
final class AuthInitial extends AuthState { const AuthInitial(); }
final class AuthLoading extends AuthState { const AuthLoading(); }
final class AuthAuthenticated extends AuthState {
final User user;
const AuthAuthenticated(this.user);
}
final class AuthUnauthenticated extends AuthState { const AuthUnauthenticated(); }
final class AuthFailure extends AuthState {
final String message;
const AuthFailure(this.message);
}
```
## BlocProvider placement
- Create `BlocProvider` at the **route level** (in {{ROUTING}} route definitions)
- `MultiBlocProvider` at route level for screens needing multiple blocs
- **NEVER** create `BlocProvider` inside a widget's `build()` method
## Usage rules
- **NEVER** call `bloc.add()` inside `build()` — only in gesture callbacks or `initState()`
- Use `BlocConsumer` only when BOTH `listen` + `build` logic are needed
- Use `BlocSelector` when only a subset of state triggers a rebuild
- Every BLoC must override `close()` and cancel `StreamSubscription`s
## BlocBuilder patterns
```dart
BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) => switch (state) {
AuthInitial() => const SizedBox.shrink(),
AuthLoading() => const LoadingIndicator(),
AuthAuthenticated(user: final u) => HomeScreen(user: u),
AuthUnauthenticated() => const LoginScreen(),
AuthFailure(message: final m) => ErrorScreen(message: m),
},
)
```
## File locations in {{PROJECT_NAME}}
- `lib/features/[feature]/presentation/bloc/[feature]_bloc.dart`
- `lib/features/[feature]/presentation/bloc/[feature]_event.dart`
- `lib/features/[feature]/presentation/bloc/[feature]_state.dart`