Módulo 04: Ecosistema Flutter Profesional

Riverpod

State Management

# Riverpod: Gestión de Estado Moderna **Riverpod** es una reescritura completa de `Provider` creada por el mismo autor (Remi Rousselet). Soluciona los problemas fundamentales de Provider (dependencia del árbol de widgets, errores en runtime) y ofrece un sistema de inyección de dependencias y gestión de estado reactivo, seguro y testearle. ## ¿Por qué Riverpod? - **Compile-safe:** No más `ProviderNotFoundException`. Si compila, funciona. - **Independiente de Flutter:** Puedes usarlo en Dart puro (backend, CLI). - **No depende del BuildContext:** Puedes leer providers desde cualquier lugar. - **Caching y Auto-dispose:** Manejo inteligente de recursos. ## Conceptos Clave ### Providers Globales En Riverpod, los providers se declaran como variables globales. No te asustes, son inmutables y seguros. ```dart // Un provider simple de solo lectura final nameProvider = Provider((ref) => 'Riverpod'); // Un provider de estado mutable final counterProvider = StateProvider((ref) => 0); ``` ### ProviderScope Debes envolver tu app en `ProviderScope` para que Riverpod funcione. ```dart void main() { runApp( ProviderScope( child: MyApp(), ), ); } ``` ## Leyendo Providers (ConsumerWidget) En lugar de `StatelessWidget`, usamos `ConsumerWidget`, que nos da acceso a un objeto `WidgetRef`. ```dart class CounterPage extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { // 1. Watch: Reconstruye el widget cuando cambia el valor final count = ref.watch(counterProvider); return Scaffold( body: Center(child: Text('$count')), floatingActionButton: FloatingActionButton( onPressed: () { // 2. Read: Lee el valor una vez (o su controlador) sin escuchar // Modificamos el estado ref.read(counterProvider.notifier).state++; }, child: Icon(Icons.add), ), ); } } ``` ## StateNotifierProvider (Lógica Compleja) Para lógica más compleja, usamos `StateNotifier` (similar a Cubit). ```dart // Estado inmutable class Todo { final String id; final String description; final bool completed; // constructor... } // Lógica de negocio class TodoList extends StateNotifier> { TodoList() : super([]); void add(String description) { state = [ ...state, Todo(id: uuid.v4(), description: description, completed: false), ]; } void toggle(String id) { state = [ for (final todo in state) if (todo.id == id) todo.copyWith(completed: !todo.completed) else todo ]; } } // Provider final todoListProvider = StateNotifierProvider>((ref) { return TodoList(); }); ``` ## FutureProvider (Datos Asíncronos) Manejar datos asíncronos es trivial con Riverpod. ```dart final configProvider = FutureProvider((ref) async { final content = await File('config.json').readAsString(); return Configuration.fromJson(jsonDecode(content)); }); class ConfigPage extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final configAsync = ref.watch(configProvider); // Maneja automáticamente los estados loading/error/data return configAsync.when( loading: () => CircularProgressIndicator(), error: (err, stack) => Text('Error: $err'), data: (config) => Text('App Name: ${config.appName}'), ); } } ``` ## Modificadores ### `.autoDispose` Destruye el estado cuando ya no se escucha (ej. al cerrar una pantalla), liberando memoria. ```dart final userProvider = FutureProvider.autoDispose.family((ref, id) async { return fetchUser(id); }); ``` ### `.family` Permite pasar parámetros a un provider. ```dart final productProvider = Provider.family((ref, productId) { return getProductById(productId); }); // Uso: ref.watch(productProvider(123)); ``` ## Conclusión Riverpod es la evolución natural de la gestión de estado en Flutter. - **Seguro:** Errores en tiempo de compilación. - **Potente:** Manejo de asincronía (`AsyncValue`) integrado. - **Flexible:** Combina providers fácilmente (`ref.watch` dentro de otro provider). - **Limpio:** Separa completamente la lógica de la UI.

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.