El paquete provider
es una solución popular para la gestión de estado en Flutter. Es fácil de usar y se integra bien con la arquitectura de Flutter, proporcionando una forma eficiente de compartir y gestionar el estado de la aplicación.
¿Qué es Provider?
provider
es un paquete que facilita la gestión de estado y la inyección de dependencias en Flutter. Utiliza el patrón de diseño de Inversión de Dependencias para proporcionar objetos a través del árbol de widgets de Flutter.
Ventajas de usar Provider:
- Simplicidad: Es fácil de entender y usar.
- Escalabilidad: Adecuado tanto para aplicaciones pequeñas como grandes.
- Integración: Se integra perfectamente con el ciclo de vida de los widgets de Flutter.
Instalación
Para usar provider
, primero debes agregarlo a tu archivo pubspec.yaml
:
Luego, ejecuta flutter pub get
para instalar el paquete.
Conceptos Básicos
ChangeNotifier
ChangeNotifier
es una clase que proporciona una forma de notificar a los oyentes cuando hay cambios en el estado. Es la base de muchos patrones de gestión de estado en Flutter.
import 'package:flutter/material.dart'; class Counter with ChangeNotifier { int _count = 0; int get count => _count; void increment() { _count++; notifyListeners(); } }
ChangeNotifierProvider
ChangeNotifierProvider
es un widget que proporciona una instancia de ChangeNotifier
a su árbol de widgets descendente.
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; void main() { runApp( ChangeNotifierProvider( create: (context) => Counter(), child: MyApp(), ), ); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: CounterScreen(), ); } }
Consumer
Consumer
es un widget que escucha los cambios en el ChangeNotifier
y reconstruye su árbol de widgets cuando hay cambios.
class CounterScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Provider Example'), ), body: Center( child: Consumer<Counter>( builder: (context, counter, child) { return Text( '${counter.count}', style: TextStyle(fontSize: 48), ); }, ), ), floatingActionButton: FloatingActionButton( onPressed: () { context.read<Counter>().increment(); }, child: Icon(Icons.add), ), ); } }
Ejemplo Completo
Aquí tienes un ejemplo completo que muestra cómo usar provider
para gestionar el estado de un contador:
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; void main() { runApp( ChangeNotifierProvider( create: (context) => Counter(), child: MyApp(), ), ); } class Counter with ChangeNotifier { int _count = 0; int get count => _count; void increment() { _count++; notifyListeners(); } } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: CounterScreen(), ); } } class CounterScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Provider Example'), ), body: Center( child: Consumer<Counter>( builder: (context, counter, child) { return Text( '${counter.count}', style: TextStyle(fontSize: 48), ); }, ), ), floatingActionButton: FloatingActionButton( onPressed: () { context.read<Counter>().increment(); }, child: Icon(Icons.add), ), ); } }
Ejercicios Prácticos
Ejercicio 1: Contador Decremental
Modifica el ejemplo anterior para que el contador también pueda decrementar. Añade un botón adicional para decrementar el contador.
Solución:
class Counter with ChangeNotifier { int _count = 0; int get count => _count; void increment() { _count++; notifyListeners(); } void decrement() { _count--; notifyListeners(); } } class CounterScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Provider Example'), ), body: Center( child: Consumer<Counter>( builder: (context, counter, child) { return Text( '${counter.count}', style: TextStyle(fontSize: 48), ); }, ), ), floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ FloatingActionButton( onPressed: () { context.read<Counter>().increment(); }, child: Icon(Icons.add), ), SizedBox(height: 10), FloatingActionButton( onPressed: () { context.read<Counter>().decrement(); }, child: Icon(Icons.remove), ), ], ), ); } }
Ejercicio 2: Estado de Autenticación
Crea una clase Auth
que gestione el estado de autenticación (logueado/no logueado) y usa provider
para mostrar diferentes pantallas dependiendo del estado de autenticación.
Solución:
class Auth with ChangeNotifier { bool _isLoggedIn = false; bool get isLoggedIn => _isLoggedIn; void login() { _isLoggedIn = true; notifyListeners(); } void logout() { _isLoggedIn = false; notifyListeners(); } } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Consumer<Auth>( builder: (context, auth, child) { return auth.isLoggedIn ? HomeScreen() : LoginScreen(); }, ), ); } } class LoginScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Login'), ), body: Center( child: ElevatedButton( onPressed: () { context.read<Auth>().login(); }, child: Text('Login'), ), ), ); } } class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Home'), actions: [ IconButton( icon: Icon(Icons.logout), onPressed: () { context.read<Auth>().logout(); }, ), ], ), body: Center( child: Text('Welcome Home!'), ), ); } }
Conclusión
En esta sección, hemos aprendido cómo usar el paquete provider
para gestionar el estado en Flutter. Hemos cubierto los conceptos básicos, incluyendo ChangeNotifier
, ChangeNotifierProvider
, y Consumer
. También hemos visto ejemplos prácticos y ejercicios para reforzar los conceptos aprendidos.
En el siguiente módulo, exploraremos más sobre la gestión de estado en Flutter, incluyendo otros paquetes y patrones como Riverpod
y el patrón Bloc
.
Curso de Desarrollo con Flutter
Módulo 1: Introducción a Flutter
- ¿Qué es Flutter?
- Configuración del Entorno de Desarrollo
- Entendiendo la Arquitectura de Flutter
- Creando Tu Primera App con Flutter
Módulo 2: Conceptos Básicos de Programación en Dart
- Introducción a Dart
- Variables y Tipos de Datos
- Sentencias de Control de Flujo
- Funciones y Métodos
- Programación Orientada a Objetos en Dart
Módulo 3: Widgets en Flutter
- Introducción a los Widgets
- Widgets Stateless vs Stateful
- Widgets Básicos
- Widgets de Diseño
- Widgets de Entrada y Formularios
Módulo 4: Gestión de Estado
Módulo 5: Navegación y Enrutamiento
- Introducción a la Navegación
- Navegación Básica
- Rutas Nombradas
- Pasando Datos Entre Pantallas
- Deep Linking
Módulo 6: Redes y APIs
- Obteniendo Datos de Internet
- Parseo de Datos JSON
- Manejo de Errores de Red
- Usando APIs REST
- Integración con GraphQL
Módulo 7: Persistencia y Almacenamiento
- Introducción a la Persistencia
- Preferencias Compartidas
- Almacenamiento de Archivos
- Base de Datos SQLite
- Usando Hive para Almacenamiento Local
Módulo 8: Conceptos Avanzados de Flutter
- Animaciones en Flutter
- Custom Paint y Canvas
- Canales de Plataforma
- Isolates y Concurrencia
- Optimización de Rendimiento
Módulo 9: Pruebas y Depuración
- Introducción a las Pruebas
- Pruebas Unitarias
- Pruebas de Widgets
- Pruebas de Integración
- Técnicas de Depuración
Módulo 10: Despliegue y Mantenimiento
- Preparación para el Lanzamiento
- Construcción para iOS
- Construcción para Android
- Integración Continua/Despliegue Continuo (CI/CD)
- Mantenimiento y Actualización de Tu App