Módulo 04: Ecosistema Flutter Profesional

Bloc Cubit

State Management

# BLoC y Cubit: Patrones de Gestión de Estado **BLoC (Business Logic Component)** es uno de los patrones de gestión de estado más populares y robustos en el ecosistema Flutter. Separa la presentación de la lógica de negocio mediante **Eventos** (entradas) y **Estados** (salidas). ## ¿Por qué BLoC? - **Separación de responsabilidades:** La UI no sabe de lógica, solo pinta estados y envía eventos. - **Testabilidad:** Al ser lógica pura Dart (sin dependencias de Flutter), es fácil de testear. - **Trazabilidad:** Sabes exactamente qué evento causó qué cambio de estado. ## Cubit vs BLoC La librería `flutter_bloc` ofrece dos herramientas: ### 1. Cubit Es una versión simplificada de BLoC. - **Entrada:** Funciones (métodos públicos). - **Salida:** Estados. - **Uso:** Casos simples donde no necesitas trazar eventos complejos. ```dart class CounterCubit extends Cubit { CounterCubit() : super(0); void increment() => emit(state + 1); void decrement() => emit(state - 1); } ``` ### 2. BLoC La versión completa basada en Streams. - **Entrada:** Eventos (clases). - **Salida:** Estados. - **Uso:** Lógica compleja, transformaciones de eventos (debounce, throttle). ```dart // Eventos abstract class CounterEvent {} class Increment extends CounterEvent {} // BLoC class CounterBloc extends Bloc { CounterBloc() : super(0) { on((event, emit) { emit(state + 1); }); } } ``` ## Implementación Práctica ### Definir Estados Siempre define una clase base y estados específicos. Usar `Equatable` ayuda a comparar estados para evitar reconstrucciones innecesarias. ```dart abstract class AuthState extends Equatable { @override List get props => []; } class AuthInitial extends AuthState {} class AuthLoading extends AuthState {} class AuthAuthenticated extends AuthState { final User user; AuthAuthenticated(this.user); @override List get props => [user]; } class AuthError extends AuthState { final String message; AuthError(this.message); @override List get props => [message]; } ``` ### Consumir en la UI #### `BlocProvider` Inyecta el BLoC en el árbol de widgets. ```dart BlocProvider( create: (context) => AuthBloc(authRepository), child: MyApp(), ) ``` #### `BlocBuilder` Reconstruye la UI cuando cambia el estado. ```dart BlocBuilder( builder: (context, state) { if (state is AuthLoading) { return CircularProgressIndicator(); } else if (state is AuthAuthenticated) { return Text('Welcome ${state.user.name}'); } else if (state is AuthError) { return Text('Error: ${state.message}'); } return LoginForm(); }, ) ``` #### `BlocListener` Ejecuta acciones (side-effects) como mostrar Snackbars o navegar, sin reconstruir la UI. ```dart BlocListener( listener: (context, state) { if (state is AuthError) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(state.message)), ); } }, child: Container(), ) ``` ## Transformación de Eventos (Solo BLoC) Una ventaja única de BLoC es poder manipular el flujo de eventos usando `rxdart` transformers. Ejemplo: **Búsqueda en tiempo real (Debounce)**. Evita llamar a la API por cada letra que escribe el usuario. ```dart EventTransformer debounce(Duration duration) { return (events, mapper) => events.debounceTime(duration).flatMap(mapper); } class SearchBloc extends Bloc { SearchBloc() : super(SearchInitial()) { on( (event, emit) async { // Lógica de búsqueda }, transformer: debounce(Duration(milliseconds: 300)), ); } } ``` ## Conclusión - Usa **Cubit** para estados simples y acciones directas. - Usa **BLoC** cuando necesites trazabilidad de eventos o transformaciones complejas. - Mantén tus estados inmutables. - Separa siempre la UI de la lógica.

Este apartado profundiza en los conceptos clave, proporcionando ejemplos prácticos y mejores prácticas para su aplicación en proyectos reales.

Al comprender estos detalles, podrás diseñar soluciones más robustas, mantenibles y escalables en tus aplicaciones Flutter y Dart.