Flutter, Bloc and Firestore Stream, la combinaison parfaite, si utilisée de la bonne manière!

This story is also available in english: Flutter, Bloc and Firestore Stream, the perfect match, if used the right way!

Esta story tambien esta disponible en español: Flutter, Bloc y Firestore Stream, ¡la combinación perfecta, si se usa de la manera correcta!

Ma toute première expérience Flutter

Alors ils m'ont donné 10 jours d'entraînement, par moi-même, en commençant avec le flutter cookbook (https://flutter.dev/docs/cookbook).

Après 2 jours de formation, honnêtement j'étais déjà fan de Flutter, un code pour Android et iOS, et desktop et web en beta (maintenant disponible, Flutter 2.0.0… YEAY !!!!), c'est tout simplement incroyable.

Donc à la fin de ma formation, prêt à commencer, ils m'ont demandé si AWS serait un bon choix pour le backend, et oui, c'est certainement le cas, mais je leur ai dit, "avez-vous également envisagé Firebase?" Je veux dire, c'est une plateforme Google, donc la compatibilité avec Flutter est probablement à 100%. Et alors devinez quoi, après cela, j’ai enfin commencé enfin à développer ma première application avec Flutter et Firebase. Heureux moi!

Le chemin du développement à la production avec ma première application n'a pas été facile, je me suis beaucoup battu avec de grosses erreurs qui ont presque coûté de l'argent à l'entreprise en factures de Google.

Je vais donc essayer d'en énumérer quelques-uns afin que cela ne vous arrivera pas.

C’est parti

Le StreamBuilder

StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance.collection('myCollection').doc(item.id).snapshots(),
builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if(snapshot.hasData) {
//Parsing your data, using setState(), etc...
} else {
//CircularProgressIndicator, handling error, etc...
}
});

Dans ces quelques lignes de code, il y a beaucoup de choses qui ne vont pas. Le premier appelle à chaque fois FirebaseFirestore.instance, FirebaseFirestore doit être instancié en tant que Singleton et pour cela, vous pouvez utiliser le plugin injectable (https://pub.dev/packages/injectable) et pour l’utiliser:

getIt<FirebaseFirestore>()

Ensuite, le DocumentSnapshot DOIT être déclaré dans votre initState si vous utilisez un StatefullWidget. Si vous ne le faites pas, chaque fois que votre widget est en cours de reconstruction, votre Stream sera de nouveau lancé jusqu'à ce que le widget soit supprimé. Imaginez que c'est un QuerySnapshot avec des centaines de documents, vous atteindrez la lecture gratuite de 50000 documents en un rien de temps et encore pire si vous utilisez setState dans le builder car cela provoquera une boucle infinie de reconstruction et ce n’est pas quelque chose que vous voulez.

Maintenant, si vous voulez vraiment le faire correctement, écrivez votre repository en utilisant injectable, utilisez le décorateur @lazySingleton, profitez de l'injection de dépendances pour injecter l'instance de FirebaseFirestore à votre classe, ce sera beaucoup plus propre. Voici un exemple de la façon dont je le fais normalement (en quelque sorte):

Normalement, l'erreur doit également être gérée dans le référentiel, j'utilise Either du package Dartz (https://pub.dev/packages/dartz) pour cela, mais c'est pour une autre story.

Utilisez des Stream avec Bloc

Et avec cela, vient écouter un Stream en utilisant le modèle de bloc.

En fait, tout cela vient d'une question que j'ai trouvée sur Slack l'autre jour et je l'ai aidé à mettre en œuvre cela. Je pense que c'est une question légitime et la réponse ne vous vient pas directement à l'esprit.

Pour ce faire, vous aurez besoin de deux événements, un pour appeler le Stream de votre repository et l'écouter et un autre à appeler lorsque de nouvelles données sont reçues.

Pour garder le même exemple que précédemment, disons que nous voulons écouter cette méthode getLogs (), je devrai créer ces deux événements:

const factory LogEvent.watchLogsAsked() = WatchLogsAsked;
const factory LogEvent.logsReceived(List<Log> data) = LogsReceived;

maintenant, dans notre fichier bloc, nous pouvons implémenter la logique pour obtenir l'état que nous voulons, mais nous devons d'abord nous abonner aux événements du Stream et Stream.listen retourner un StreamSubscription afin que nous ayons:

StreamSubscription<List<Log>> _logsStreamSubscription;

Nous pouvons donc continuer et retourner notre State avec un yield:

yield* event.map(
watchLogsAsked: (WatchLogsAsked _) async* {
yield state.copyWith(logsAreLoading: true);
await _logStreamSubscription?.cancel();
_logsStreamSubscription = _repository.getLogs().listen((data) => add(LogEvent.logsReceived(data)));
},
logsReceived: (LogsReceived data) async* {
//Do your stuff here and yield your state
}
);

Et c'est fondamentalement tout, maintenant vous pouvez appeler BlocBuilder dans votre StatelessWidget et faire tout ce que vous voulez avec vos données, sachant que ce sera la seule partie à reconstruire lorsque de nouvelles données arriveront;

Et n'oubliez pas d'annuler votre Subscription également, remplacez simplement la méthode Bloc close() et annulez l'abonnement avec un cancel().

Voici un exemple de comment je l’implémente:

Vous pouvez voir que j'utilise Freezed pour la génération de code et Either pour la gestion des erreurs, si vous voulez en savoir plus à ce sujet, il y a beaucoup de tutoriels ici qui vous expliqueront comment cela fonctionne mieux que moi.

Eh bien, voila pour l’histoire, et c'est juste mon point de vue, nous savons tous qu'il y en a beaucoup et je ne prétends pas que cela soit la meilleure. Ce n'est qu'une possibilité et il y en a beaucoup d'autres, c'est l'une des meilleures choses que nous ayons, nous pouvons toujours apprendre de nouvelles choses, On ne s’ennuie jamais.

N'hésitez pas à me dire ce que vous pensez, si vous aimez ou n'aimez pas et pourquoi.

Happy coding @ tous!

Flutter Developer enthousiast since 2018

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store