Uso de Provider para Gestión de Estado en Flutter

Clase 18 de 26Curso de Flutter

Contenido del curso

Resumen

Gestionar el estado de una aplicación en Flutter puede volverse complejo cuando la lógica de datos y la interfaz conviven en el mismo archivo. La librería Provider resuelve este problema al permitir inyectar y compartir estado entre widgets, separando la lógica de negocio de la capa visual. A continuación se explica paso a paso cómo instalar, configurar y consumir un provider para obtener datos de una API de recetas.

¿Cómo instalar la librería Provider en Flutter?

Antes de escribir cualquier línea de código relacionada con providers, es necesario agregar la dependencia al proyecto. En el archivo de dependencias se coloca provider con la versión deseada, en este caso una mayor a la versión 6.0.0 [0:49]. Después se ejecuta el comando flutter pub get en la terminal para asegurar que todas las dependencias estén actualizadas y disponibles [1:07].

Una vez instalada la librería, conviene crear una carpeta dedicada dentro de la estructura del proyecto para guardar todos los providers. Esto mantiene el código organizado y facilita el mantenimiento a largo plazo.

¿Cómo crear un provider con ChangeNotifier?

Dentro de la carpeta recién creada se genera un archivo llamado recipes_provider.dart. La clase RecipesProvider debe extender de ChangeNotifier [1:37], una clase fundamental que permite mantener una escucha constante de todos los cambios que ocurren durante las llamadas a datos.

¿Qué variables necesita el provider?

Se definen dos variables esenciales:

  • isLoading: un booleano que inicia en false y controla cuándo los datos están cargando [2:02].
  • recipes: una lista tipada con el modelo Recipe, que almacena las recetas obtenidas de la API [2:13].

¿Cómo se estructura la función fetchRecipes?

La función fetchRecipes se traslada desde el widget home al provider [1:52]. Su flujo es el siguiente:

  • Al iniciar, se establece isLoading = true y se llama a notifyListeners para avisar a los widgets que algo cambió [2:32].
  • Se realiza la llamada HTTP importando la librería correspondiente con un alias [3:00].
  • La respuesta se decodifica con jsonDecode y se mapea cada elemento al modelo Recipe usando fromJSON [3:30].
  • En caso de error, se retorna una lista vacía.
  • En el bloque finally se establece isLoading = false y se cierra la escucha con notifyListeners nuevamente [4:24]. Esto garantiza que, sin importar el resultado, la carga finalice correctamente.

¿Cómo consumir el provider desde los widgets?

Con la lógica migrada al provider, el widget home se simplifica considerablemente. Se elimina la llamada directa a la API y se reemplaza por una referencia al provider [4:46].

¿Cómo se conecta el provider al widget?

Se crea una variable recipesProvider utilizando Provider.of<RecipesProvider>(context, listen: false) [4:56]. Luego se invoca recipesProvider.fetchRecipes() para disparar la obtención de datos [5:22].

En lugar de un FutureBuilder, se utiliza un Consumer tipado con el provider [5:38]. El Consumer recibe tres parámetros: context, provider y child. Dentro de su builder se accede directamente a las variables del provider:

  • Si provider.isLoading es true, se muestra un CircularProgressIndicator [6:03].
  • Si provider.recipes.isEmpty, se muestra un mensaje indicando que no hay datos [6:28].
  • En caso contrario, se renderiza la lista de recetas accediendo a propiedades como recipe.name, recipe.imageLink y recipe.author [7:22].

¿Cómo registrar el provider en el archivo main?

Es indispensable envolver el MaterialApp con un MultiProvider en el archivo main.dart [6:54]. Dentro del arreglo de providers se registra un ChangeNotifierProvider que crea una instancia de RecipesProvider [7:04]. De esta forma, toda la aplicación puede acceder al provider desde cualquier punto del árbol de widgets.

dart MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => RecipesProvider()), ], child: MaterialApp(...), )

Con este patrón se logra una separación clara entre la lógica de datos y la interfaz visual. El provider se encarga de las llamadas, el modelo maneja la serialización con fromJSON y toJSON, y los widgets simplemente consumen la información lista para mostrar [8:03]. Si ya implementaste este patrón en tu proyecto, comparte cómo organizas tus providers y qué mejoras has notado en la mantenibilidad de tu código.