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:

dependencies:
  flutter:
    sdk: flutter
  provider: ^6.0.0

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

Módulo 2: Conceptos Básicos de Programación en Dart

Módulo 3: Widgets en Flutter

Módulo 4: Gestión de Estado

Módulo 5: Navegación y Enrutamiento

Módulo 6: Redes y APIs

Módulo 7: Persistencia y Almacenamiento

Módulo 8: Conceptos Avanzados de Flutter

Módulo 9: Pruebas y Depuración

Módulo 10: Despliegue y Mantenimiento

Módulo 11: Flutter para Web y Escritorio

© Copyright 2024. Todos los derechos reservados