Bueno llegamos a uno de los temas más sonados del mundo Flutter, los gestores de estados. En este libro hemos hablado varias veces de la gestión de estados recuerda repasar el contenido previamente expuesto:

Capítulo 4- Los estados en Flutter, el fundamento para todos tus desarrollos

Capítulo 9 - Comprendiendo los estados de Aplicación con InheritedWidget

Al ir evolucionando Flutter, su comunidad comenzó a desarrollar soluciones que fueran fáciles de entender para la gestión de los estados. Existen muchos paquetes famosos para la gestión de estados.

En este capítulo veremos como podemos resolver un mismo ejemplo con los gestores de estados más usados en el mercado y que recomiendo usar a saber Provider, Bloc y Riverpod. ¡Lo se! estarás pensando pero ¿No existen muchos más paquetes? si bien esto es verdad considero que con estos te puedes defender para aprender cualquier otro gestor de estados.

El ejemplo que estaremos realizando es una app que permitirá, tener un campo de texto para agregar elementos a una lista y estos podrán ser editados y observados desde cualquier parte de la app. También haremos la gestión de una imagen que muestra a un gato en sus diferentes estados (corriendo, comiendo, durmiendo, saltando, jugando).

Ejemplo Provider

Comenzaremos con Provider, un paquete muy popular en Flutter. Realmente no es un gestor de estados sino que provider nos permite hacer inversión de dependencias, pero la comunidad ha visto su potencial para gestionar los estados. Veamos cómo hacerlo, comenzando por la creación de los providers:

import 'package:flutter/material.dart';

class CatProvider with ChangeNotifier {
  static const initialPath = 'assets/images/';
  String currentImageCat = '${initialPath}cat-eat.png';
  String currentAction = 'comiendo';

  void catEat() {
    currentImageCat = '${initialPath}cat-eat.png';
    currentAction = 'comiendo';
    notifyListeners();
  }

  void catSleep() {
    currentImageCat = '${initialPath}cat-sleep.png';
    currentAction = 'durmiendo';
    notifyListeners();
  }

  void catJump() {
    currentImageCat = '${initialPath}cat-jump.png';
    currentAction = 'saltando';
    notifyListeners();
  }

  void catRunning() {
    currentImageCat = '${initialPath}cat-running.png';
    currentAction = 'corriendo';
    notifyListeners();
  }

  void catPlay() {
    currentImageCat = '${initialPath}cat-play.png';
    currentAction = 'jugando';
    notifyListeners();
  }
}

Este código define una clase en Flutter llamada CatProvider. Esta clase se utiliza para gestionar los estados de un gato en una aplicación.

La clase CatProvider tiene tres propiedades: initialPath, currentImageCat y currentAction. initialPath es una constante que define la ubicación inicial de las imágenes del gato. currentImageCat y currentAction son usadas para almacenar la imagen actual del gato y la acción que está realizando.

La clase CatProvider también tiene cinco métodos: catEat(), catSleep(), catJump(), catRunning(), y catPlay(). Cada uno de estos métodos cambia las propiedades currentImageCat y currentAction a un estado y acción específicos, y luego notifica a los oyentes sobre este cambio. Por ejemplo, si el método catEat() es llamado, la imagen del gato cambiará a 'cat-eat.png' y la acción a 'comiendo'.

La notificación a los oyentes se realiza mediante la función notifyListeners(), que se encarga de informar a todos los elementos de la interfaz que están escuchando al CatProvider que ha habido un cambio en su estado, y que deben actualizar su información.

Para la lista de compras hacemos algo similar :

import 'package:flutter/material.dart';

class ShoppingListProvider with ChangeNotifier {
  List<String> items = [];

  void addItem(String newItem) {
    items.add(newItem);
    notifyListeners();
  }

  void removeItem(int index) {
    items.removeAt(index);
    notifyListeners();
  }
}

Ahora veamos cómo se debe configurar nuestra app para que pueda observar la información:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:provider_example/config/providers/cat.dart';
import 'package:provider_example/config/providers/shopping_list.dart';
import 'package:provider_example/config/routes/app_routes.dart';
import 'package:provider_example/screens/cat_page.dart';
import 'package:provider_example/screens/home.dart';
import 'package:weinds/foundations/themes/weinds_themes.dart';

class ProviderExampleApp extends StatelessWidget {
  const ProviderExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => CatProvider()),
        ChangeNotifierProvider(create: (context) => ShoppingListProvider()),
      ],
      child: MaterialApp(
        theme: ligthThemeWeincode,
        onGenerateRoute: (settings) {
          switch (settings.name) {
            case AppRoutes.home:
              return MaterialPageRoute(builder: (context) => const HomePage());
            case AppRoutes.catState:
              return MaterialPageRoute(
                  builder: (context) => const CatStatePage());
            default:
              return MaterialPageRoute(builder: (context) => const HomePage());
          }
        },
      ),
    );
  }
}