Saltar al contenido principal

State Management en Flutter

Instrucciones sobre cómo manejar el state con ChangeNotifiers.

Aprende a crear un ViewModel con ChangeNotifier y a manejar los states de carga, éxito y error.

Qué lograrás

Crea un ViewModel con ChangeNotifier
Maneja los states de carga, éxito y error
Señala actualizaciones de la UI con notifyListeners

Pasos

1

Introducción

Cuando los desarrolladores hablan de State Management en Flutter, básicamente se refieren al patrón mediante el cual tu app actualiza los datos que necesita para renderizarse correctamente y luego le dice a Flutter que vuelva a renderizar la UI con esos nuevos datos.

En MVVM, esta responsabilidad recae en la capa ViewModel, que se encuentra entre la UI y la capa Model y las conecta. En Flutter, los ViewModels usan la clase ChangeNotifier de Flutter para notificar a la UI cuando cambian los datos.

Para usar ChangeNotifier, extiéndelo en tu clase de State Management para obtener acceso al método notifyListeners(), el cual activa reconstrucciones de la UI cuando es llamado.

2

Crea la estructura básica del view model

Crea la clase ArticleViewModel con su estructura básica y propiedades de state:

dart
class ArticleViewModel extends ChangeNotifier {
  final ArticleModel model;
  Summary? summary;
  Exception? error;
  bool isLoading = false;

  ArticleViewModel(this.model);
}

El ArticleViewModel contiene tres elementos de state:

  • summary: Los datos actuales del artículo de Wikipedia.
  • error: Cualquier error que haya ocurrido durante la obtención de datos.
  • isLoading: Una bandera para mostrar indicadores de progreso.
3

Agrega la inicialización del constructor

Actualiza el constructor para obtener contenido automáticamente cuando se cree el ArticleViewModel:

dart
class ArticleViewModel extends ChangeNotifier {
  final ArticleModel model;
  Summary? summary;
  Exception? error;
  bool isLoading = false;

  ArticleViewModel(this.model) {
    fetchArticle();
  }

  // Methods will be added next.
  Future<void> fetchArticle() async {}
}

Esta inicialización del constructor proporciona contenido inmediato cuando se crea un objeto ArticleViewModel. Como los constructores no pueden ser asíncronos, delega la obtención de contenido inicial en un método separado.

4

Configura el método fetchArticle

Agrega el método fetchArticle que obtiene datos y maneja las actualizaciones de state:

dart
class ArticleViewModel extends ChangeNotifier {
  final ArticleModel model;
  Summary? summary;
  Exception? error;
  bool isLoading = false;

  ArticleViewModel(this.model) {
    fetchArticle();
  }

  Future<void> fetchArticle() async {
    isLoading = true;
    notifyListeners();

    // TODO: Add data fetching logic

    isLoading = false;
    notifyListeners();
  }
}

El ViewModel actualiza la propiedad isLoading y llama a notifyListeners() para informar a la UI sobre la actualización. Cuando la operación se completa, cambia la propiedad de nuevo. Cuando construyas la UI, usarás esta propiedad isLoading para mostrar un indicador de carga mientras se obtiene un nuevo artículo.

5

Obtén un artículo desde el ArticleModel

Completa el método fetchArticle para obtener el resumen de un artículo. Usa un bloque try-catch para manejar con elegancia los errores de red y almacenar los mensajes de error que la UI puede mostrar a los usuarios. El método limpia los errores anteriores en caso de éxito y limpia el resumen del artículo anterior en caso de error para mantener un state consistente.

dart
class ArticleViewModel extends ChangeNotifier {
  final ArticleModel model;
  Summary? summary;
  Exception? error;
  bool isLoading = false;

  ArticleViewModel(this.model) {
    fetchArticle();
  }

  Future<void> fetchArticle() async {
    isLoading = true;
    notifyListeners();
    try {
      summary = await model.getRandomArticleSummary();
      error = null; // Clear any previous errors.
    } on HttpException catch (e) {
      error = e;
      summary = null;
    }
    isLoading = false;
    notifyListeners();
  }
}
6

Prueba el ViewModel

Antes de construir la UI completa, prueba que tus peticiones HTTP funcionen imprimiendo los resultados en la consola. Primero, actualiza el método fetchArticle para imprimir los resultados:

dart
Future<void> fetchArticle() async {
  isLoading = true;
  notifyListeners();
  try {
    summary = await model.getRandomArticleSummary();
    print('Article loaded: ${summary!.titles.normalized}'); // Temporary
    error = null; // Clear any previous errors.
  } on HttpException catch (e) {
    print('Error loading article: ${e.message}'); // Temporary
    error = e;
    summary = null;
  }
  isLoading = false;
  notifyListeners();
}

Luego, actualiza el widget MainApp para crear el ArticleViewModel, el cual llama al método fetchArticle al ser creado:

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

  @override
  Widget build(BuildContext context) {
    // Instantiate your `ArticleViewModel` to test its HTTP requests.
    final viewModel = ArticleViewModel(ArticleModel());

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Wikipedia Flutter')),
        body: const Center(child: Text('Check console for article data')),
      ),
    );
  }
}

Haz Hot Reload en tu app y revisa la salida de tu consola. Deberías ver el título de un artículo o un mensaje de error, lo que confirma que tu Model y ViewModel están conectados correctamente.

7

Revisión

Qué lograste

Aquí tienes un resumen de lo que construiste y aprendiste en esta lección.
Se creó el ArticleViewModel con ChangeNotifier

El ViewModel se sitúa entre tu UI y tu Model, manejando el state y conectando las dos capas. Al extender de ChangeNotifier, tu ViewModel adquiere la capacidad de notificar a los oyentes cuando cambian los datos.

Manejó los states de carga, éxito y error

Tu ViewModel rastrea tres elementos de state: isLoading, summary y error. Usando try y catch, manejas los errores de red con elegancia y mantienes un state consistente para cada resultado posible.

Usó notifyListeners para señalar actualizaciones de la UI

Llamar a notifyListeners() indica a cualquier widget oyente que se reconstruya. Lo llamas después de establecer loading = true y nuevamente después de que se completa la operación. Así es como puedes implementar actualizaciones reactivas de la UI en Flutter.

8

Ponte a prueba

Quiz de State Management

1 / 2
What is a ChangeNotifier?
  1. Un tipo de controlador de animación en Flutter.

    No exactamente.

    Los controladores de animación son independientes; ChangeNotifier es para State Management.

  2. Una clase que puede notificar a los oyentes cuando cambian sus datos, permitiendo actualizaciones reactivas de la UI.

    ¡Así es!

    ChangeNotifier proporciona el método notifyListeners para indicar a los widgets que se reconstruyan cuando cambia el state.

  3. Un widget que muestra notificaciones al usuario.

    No exactamente.

    ChangeNotifier no es un widget; es una clase para manejar el state.

  4. Una clase interna de Dart para enviar notificaciones push.

    No exactamente.

    ChangeNotifier es para State Management interno de la app, no para notificaciones push.

What does calling notifyListeners() do in a ChangeNotifier?
  1. Restablece todas las propiedades de state a sus valores predeterminados.

    No exactamente.

    notifyListeners() no modifica el state; solo indica que el state ha cambiado.

  2. Indica a cualquier widget oyente que se reconstruya y refleje el nuevo state.

    ¡Así es!

    Llamar a notifyListeners() activa una reconstrucción de todos los widgets que escuchan a este ChangeNotifier.

  3. Registra el cambio de state en la consola para depuración.

    No exactamente.

    No registra nada; indica a los oyentes que se reconstruyan.

  4. Guarda el state actual en el almacenamiento local.

    No exactamente.

    notifyListeners() señala actualizaciones de la UI; la persistencia requiere una implementación separada.