En este artículo explicaré cómo funciona el BLoC Pattern de Flutter. Tengo un boilerplate de flutter en el Github de LeanMind, que quizás sea de ayuda para seguir este post.
Pero primero vamos a hacer una pequeña introducción. Este patrón fue presentado en la Dart Conference de 2018 📹, es decir, es bastante nuevo. El objetivo de Paolo Soares y Cong Hu (trabajadores de Google), era hacer que el código fuera reutilizable entre las aplicaciones móviles hechas con Flutter y las aplicaciones web hechas con Angular Dart.
El concepto principal es que exista una capa intermedia entre las vistas y el modelo. Esta capa gestionará los estados y manejará los datos, dependiendo de los eventos que se reciban de la vista.
He dibujado este diagrama: 🎨
A partir de ahora, todo el código que veamos estará directamente relacionado con el diagrama y la llamaremos “perfil”.
Crearemos el código mínimo necesario, dividido en cuatro ficheros:
|
|
Estos son los paquetes que usaremos, hay que añadirlos en el pubspec.yaml
:
flutter_bloc
Para crear el bloc y, posteriormente, para utilizarlo en la vistabuilt_value
Se hará cargo de generar objetos inmutables entre otras cosasbuild_runner
Será quien autogenere el código necesarioSabiendo esto, empecemos a crear el estado inicial, lo llamaremos InitialState y no tendrá ninguna propiedad.
|
|
Uhm… quizás sea necesario explicarlo:
💭 Es una clase abstracta llamada InitialState que extenderá de nuestra clase ProfileState anteriormente creada e implementará el Built de sí mismo. Dentro, creamos el constructor privado para que sea inaccesible desde fuera y una factoría que recibe una función (opcional) para construir el estado, más adelante veremos cómo se construye cuando necesita parámetros.
Hecho eso, vamos a tener que añadir justo después de los imports la siguiente línea de código:
|
|
Lanzaremos el comando flutter pub run build_runner watch --delete-conflicting-outputs
que ejecutará el paquete build_runner
y autogenerará el código necesario en el fichero especificado para hacer funcionar nuestro InitialState.
¡Perfecto! 👏 Hemos creado nuestro primer estado… pero no se utiliza en ningún momento, así que vamos a indicárselo a nuestro bloc:
|
|
Teniendo este estado, vamos a tener que asociar la vista con el bloc ¿Cómo? Pues con el BlocBuilder (de flutter_bloc
):
|
|
Así, cada vez que nuestro estado cambie, la vista se dará cuenta y pintará lo que haga falta dependiendo del estado. Como por ahora solamente tenemos uno, pintará un spinner en el centro de la pantalla.
Toca crear el evento que hará pedir la información al repository. Seguimos exactamente el mismo proceso que hicimos con el estado, pero con un evento que llamaremos LoadDataEvent
:
|
|
Ahora que ya tenemos el evento, tenemos que lanzarlo cuando el estado sea InitialState:
|
|
Aquí hay varios puntos importantes:
BlocProvider.of<ProfileBloc>(context)
.Pasamos al bloc. En la función mapEventToState
añadiremos nuestro evento y pediremos al repository los datos tal que así:
|
|
Vale… sí, tenemos los datos, pero… ¿y ahora qué? Pues tendremos que crear los siguientes estados. Según nuestro diagrama, cuando se lanza el evento LoadDataEvent, pasará a estar en el estado LoadingState, pedirá los datos al repository y el estado cambiará a RecoveredDataState. Es decir, vamos a tener que crear estos dos estados nuevos ¡Al lío!
El estado LoadingState tampoco tendrá ninguna propiedad, ya que no necesitamos que tenga ningún tipo de dato a la hora de mostrar en pantalla el spinner, así que será así:
|
|
Nada nuevo, es prácticamente igual que el InitialState. Ahora pasemos al estado RecoveredDataState, que sí tendrá propiedades. Esta será la única diferencia:
|
|
¡Guau, ya tenemos tres estados! 😄 Ahora volvamos al bloc y terminemos el evento LoadDataEvent:
|
|
¿yield
? ¿async*
? Seguramente te diste cuenta antes, pero… ¿qué es esto? No quiero entrar mucho en detalle ahora, así que te recomiendo que leas este artículo, está en inglés, pero creo que se entiende bastante bien.
Por otro lado, también es importante resaltar el estado RecoveredDataState, estamos pasándole el nombre a través del builder que es el que se autogeneró en el estado, imagínate que también tuvieramos el apellido, ¿cómo se lo pasaríamos? Pues así:
|
|
Es un poco extraño, ¿no? 🤔 Pues realmente es lo mismo que si hicieramos así:
|
|
Bien, vayamos a la vista. Estamos mandando dos nuevos estados a la vista, pero esta no va a cambiar, porque no lo estamos controlando:
|
|
Podemos comprobar que en cualquier estado va a aparecer el spinner, excepto si el estado es RecoveredDataState, que significará que tendremos en el estado el nombre (state.name
) y podremos pintarlo.
Para completar el diagrama, faltaría cambiar lo que mostramos en el estado RecoveredDataState por un TextField, con el nombre y un RaisedButton (o similar), para que cuando se presione el botón, lance un evento con el nuevo valor del TextField, el bloc escuche este evento y pase por los otros estados, ErrorState ❌ o SuccessState ✔. Sin embargo, con lo que hemos visto, creo que es suficiente para entender que la vista se construye basándonos en los estados y que los estados cambian en relación con los eventos que les mandes.
Espero que realmente te haya servido de algo leer este post y te animo a completar el diagrama. Si quieres contactar conmigo porque tienes alguna duda o sugerencia, puedes escribirme a mi correo michael.reyes@leanmind.es 📥.
¡Muchas gracias por leerme! 📖
¿Quieres más? te invitamos a suscribirte a nuestro boletín para avisarte cada vez que recopilemos contenido de calidad que compartir.
Si disfrutas leyendo nuestro blog, ¿imaginas lo divertido que sería trabajar con nosotros? ¿te gustaría?
Pero espera 🖐 que tenemos un conflicto interno. A nosotros las newsletter nos parecen 💩👎👹 Por eso hemos creado la LEAN LISTA, la primera lista zen, disfrutona y que suena a rock y reggaeton del sector de la programación. Todos hemos recibido newsletters por encima de nuestras posibilidades 😅 por eso este es el compromiso de la Lean Lista