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
