Gestion des états : SetState, ChangeNotifier, Provider, Riverpod

Bonjour à tous,

J’ai commencé à regarder le cours sur Flutter Avancé (Router + Architecture).
Avant de commencer les cours de Purple Giraffe, j’avais pris connaissance des Providers et de la bibliotheque riverpod. (mais jamais reussi à mettre en place !)
Je m’attendais à l’utilisation des Providers justement dans le cours de Flutter Avancé.
Et là, bam, ChangeNotifier + AnimatedBuilder !

Déjà que la notion de gestion des états n’était pas claire pour moi, j’avoue que je coule d’un mètre de plus :slight_smile:

De ce que j’ai compris à travers les cours et ce que j’ai trouvé, en résumé :
→ setState() permet la gestion des états pour des applications simples (1 écran ou 1 écrans maximum)
→ ChangeNotifier + AnimatedBuilder : permet de rafraichir plusieurs widgets abonnés à une classe dans un nombre d’écrans llimités. Cette solution offre un panel de possibilités plus important par rapport au setState
→ Provider : permet de gérer les états dans une classe à part et de les partager à différents écrans en les écoutant (read / watch, j’en sais rien : je n’ai pas saisi la subtilité encore :slight_smile: ). Cette solution permet la gestion des états dans une application composée de nombreux écrans (à partir de combien ?)
→ riverpod : c’est une bibliotheque non officielle qui permet d’etre plus « précis dans la déclaration du type de gestion d’états » (Future, Stream, StateNotifier, etc…). Tous se base sur la classe Provider mais apporte des fonctionnalités supplémentaires

1ere question : est ce que ma compréhension est correcte des différentes solutions ?
2eme question : j’ai du mal à voir la limite de ChangeNotifier (dans mon esprit c’est moins bien que Provider pour des applications complexes. à tort ?). Jusqu’ou je peux utiliser ChangeNotifier et à partir de quand utiliser Provider ?
3eme question : inutile de partir sur riverpod quand on ne matrise pas les Providers ?
4eme question : si un jour Maxime cherche un nouveau sujet de cours, je propose « les différentes solution pour la gestion des états » :slight_smile:

Merci encore pour tous ces cours très clairs et très pédagogue, qui m’ont fait gagner un temps fou en compréhension.
Ils sont top !

Merci d’avance pour vos réponses

2 « J'aime »

Merci pour ce retour et cette analyse!
Comme tu l’as remarqué il existe de multiples façons de gérer l’état dans une app Flutter.
En fonction des personnes, certains t’orienteront dans un sens, et d’autres prendront une autre direction.
Il faut surtout comprendre que dans tous les cas tu peux y arriver avec chacune de ces solutions, mais le principal problème sera le couplage et la modularité de tes classes

Le besoin

J’ai des infos dans un écran 1, et je veux récupérer ces infos dans un écran 2.

Mon analyse

Je considère les écrans et widgets comme des interfaces finales de nos apps. Ils servent à présenter des infos aux utilisateurs, ou à leur en demander. En aucun cas un écran ne devrait posséder des données de mon app.
Des couches logicielles internes sont là pour cela et les widgets ne sont que des intermédiaires qui vont présenter ces données d’une certaine façon.
Si un écran 2 veut les infos d’un écran 1, en réalité ces données ont déjà été transférées à la couche interne et c’est à elle de les fournir à l’écran 2.
Selon ma vision des choses, les écrans ne devraient JAMAIS communiquer entre eux.

Provider

La solution de type Provider crée un lien invisible entre les écrans (ou d’autres types d’objets) pour leur permettre de communiquer entre eux sans se connaître.
Je n’aime pas cette solution car elle est souvent utilisée pour faire communiquer un widget avec un autre.

Riverpod

Je ne l’ai jamais utilisé car je n’en ai jamais eu besoin puisque le Framework officiel fournit déjà tous les outils nécessaire. Je reviendrai plus tard sur ce point

setState

Ton analyse est bonne, il est utile pour gérer de la logique interne à un widget. Pour une app très basique où tu n’as pas de séparation UI/data alors ça va très bien. Mais dès que tu veux avoir plusieurs écrans et un minimum d’organisation tu seras limité.
Je me sers parfois de setState dans de gros projets : pour des petits widgets avec un peu de logique interne. Ce sont généralement des widgets graphiques réutilisables.

AnimatedBuilder + ChangeNotifier

Ces 2 classes permettent à un Widget de surveiller un objet tiers, pour se redessiner si quelque chose change dans l’objet externe.
Je suppose que Riverpod doit permettre de faire la même chose d’ailleurs.
Mais l’objectif du cours était de permettre une véritable architecture organisées SANS utiliser de dépendance externe.

Concernant tes questions :

Oui ton analyse semble bonne, mais je connais très peu Provider et Riverpod

J’utilise la technique AnimatedBuilder + ChangeNotifier sur des projets conséquents (app de Purple Giraffe, backoffice de gestion web de l’app Purple Giraffe, grosse app de billetterie qui va bientôt sortir, etc.) sans aucun problème.
Même une app complexe sera découpée en plusieurs écrans simples. Si tu as une architecture claire, tu auras des couches internes nombreuses et beaucoup de classes, mais à chaque écran tu pourras utiliser cette technique sans problème.

Si tu veux mon avis : inutile de partir sur Riverpod ni Provider :grin:

Justement, le cours Flutter : Architecture et Navigation a été créé pour cette raison : il existe pleins de méthodes qui s’affrontent.
En voici une qui :

  • fonctionne très bien
  • scale très bien pour des apps complexes
  • ne requiert aucune dépendance externe à Flutter

Note sur les dépendances externes

Autant que possible j’essaie toujours de limiter ces dépendances externes car :

  • elles peuvent être abandonnées à tout moment par leur créateur
  • elles peuvent être en retard par rapport au framework
  • elles peuvent poser des problèmes de dépendances lors des mises à jour de Flutter
  • elles intègrent du code externe dans mon app et je n’ai pas forcément le temps de vérifier tout leur code
  • elles requièrent un temps de formation supplémentaire pour les apprendre
  • elles requièrent du temps de formation supplémentaire à chacune de leurs mises à jour
  • elles peuvent demander d’effectuer des migrations de code lors de breaking changes

J’utilise des lib externes, mais uniquement lorsque je n’ai pas le choix.

Résumé de ce long post :grin:

Il existe des tas de systèmes de gestion d’état et ils sont tous valables. Pour plusieurs raisons, je préfère utiliser celui intégré à Flutter (AnimatedBuilder + ChangeNotifier) et je m’en sert avec plaisir sur des projets de toutes tailles.
C’est donc celui que je vous recommande et présente en détail dans le cours Flutter : Architecture et Navigation

Merci à toi pour ce retour et cette question intéressante :slight_smile:

Happy coding!

3 « J'aime »

Je te remercie vraiment d’avoir pris le temps de me répondre avec autant de détails !

Tes explications sont très claires. Le sujet était très floue entre ces différentes solutions et je ne savais pas sur laquelle partir pour pouvoir réaliser des projets de taille « correcte ».

J’avais relevé pendant tes cours ton apétence pour les dépences externes. :slight_smile: Mais j’avais l’impression, à travers mes lectures, que Riverpod était LA solution.
Je comprends ton point de vue sur la communication entre les widgets, et je t’avouerai qu’il me plait bien. Ca me plaira peut etre encore plus quand mon code marchera du début à la fin :smiley:

Je suis arrivé au bout du cours Flutter : Architecture et Navigation.
J’ai COMPRIS ce que j’arrivais à faire marcher ! Oui car des fois ca marche mais on ne sait pas trop expliquer pourquoi :smiley:
Je vais le refaire car il y a beaucoup d’information et ce n’est pas évident de tout assimiler du 1er coup.

En tout cas, j’ai bien compris que AnimatedBuilder + ChangeNotifier peut me permettre de faire de très applications en utilisant une solution relativement simple, qui respecte le principe « pas de communication directe entre les widgets » et qui coincide avec une architecture maintenable au sens large

Merci encore pour toutes explications

@mbritto je reviens juste sur la question des providers, car je suis confronté un problème de mon côté : je dois faire réagir l’UI à un changement d’état de Directus (opéré par des apps tierces). Dans ce cas, mon app centrale, celle qui gère le système, ne fait rien, mais doit être mise à jour. Le provider peut dans ce cas être une solution non ?

Merci

Tu peux mais ça n’est pas obligatoire. Si on reste sur le modèle du cours, tu peux très bien prévenir ton routeur lorsqu’un évènement est reçu par une couche de données.
Ensuite ton routeur peut décider :

  • d’afficher un écran avec cette information
  • de trouver l’écran/viewmodel déjà affiché qui a besoin de l’info et la lui transmettre

Autre solution possible sans passer par le routeur :

  • ton viewmodel peut s’enregistrer auprès d’une couche de données pour être prévenu lorsque un evenement survient

Le provider fait la même chose que ce que tu peux faire avec des classes Dart classiques. Donc tout ce que peut faire le Provider est aussi possible sans cette dépendance.