Bonjour, Habr! En présentant une traduction de l'article,
laissez-moi vous aider à comprendre et à choisir une solution de gestion d'état pour votre application , qui a attiré mon attention et s'est intéressée au processus d'apprentissage des bases de la gestion d'état à Flutter. Je serai heureux d'entendre toute critique concernant cette traduction. Dans les guillemets (``) seront écrits mes pensées et explications personnelles.

La gestion de l'état de flottement est un sujet brûlant. Il existe de nombreuses solutions possibles au problème, et en s'y confondant, choisir la plus adaptée à vos besoins est extrêmement simple. J'étais moi-même confus, mais j'ai trouvé une solution appropriée. Permettez-moi de le partager avec vous.
Pour trouver une solution adaptée à vos besoins, vous devez déterminer les besoins eux-mêmes. Dans mon cas, c'est:
- Avoir l'opportunité de développer le projet sans compromettre la qualité du code
- Séparez la logique d'affichage de la logique métier
- Avoir un code clair difficile à briser
- Prévisibilité et compréhensibilité du code
Compte tenu de ces exigences, les options appropriées restent:
- Utilisation de la
setState()
et des widgets avec état - ScopedModel `Library`
- Utilisation du modèle BLoC (composants de logique applicative)
- Redux
La différence entre l'état local et mondial
Avant de vous lancer dans l'analyse des solutions sélectionnées, vous devez comprendre la différence entre l'état local et l'état global. Un exemple pratique convient à cela:
Imaginez un formulaire d'autorisation, où l'utilisateur est invité à entrer un nom d'utilisateur et un mot de passe et à obtenir l'objet "identité d'utilisateur" après avoir envoyé le formulaire. Dans cet exemple, toute vérification des données entrées dans les champs du formulaire fera partie de l'état local du «widget de formulaire d'autorisation», et le reste de l'application ne devrait pas en être conscient. Et l'objet «identité» renvoyé par le «serveur d'autorisation» fait partie de l'état global. Ainsi, d'autres composants dépendent de cet objet, changeant de comportement selon que l'utilisateur est autorisé ou non.
Brèves conclusions pour ceux qui en ont assez d'attendreSi vous ne voulez pas attendre ou si vous n'êtes pas intéressé par mes recherches, voici un bref aperçu des résultats:

Ma recommandation est d'utiliser BLoC pour la gestion de l'état local et Redux pour l'état global, surtout si vous créez une application complexe qui grandira avec le temps.
Pourquoi vous ne devriez pas utiliser setState ()
L'utilisation de
setState()
dans vos widgets est idéale pour prototyper rapidement et obtenir des commentaires sur ces changements, mais cette manière ne nous aide pas à atteindre nos objectifs, car la logique d'affichage est mélangée à la logique métier, ce qui viole le principe de propreté et de qualité du code. La maintenance d'un tel code sera difficile à l'avenir, par conséquent, à l'exception du prototypage, cette approche n'est pas recommandée.
ScopedModel - un pas dans la bonne direction
ScopedModel est une bibliothèque tierce de
Brian Egan . Il permet de créer des objets
Models
spéciaux, ainsi que d'utiliser la méthode
notifyListeners()
si nécessaire. Par exemple, pour suivre tout changement dans les propriétés d'un objet modèle:
class CounterModel extends Model { int _counter = 0; int get counter = _counter; void increment() { _counter++; notifyListeners(); } }
Dans nos widgets, nous serons en mesure de répondre aux changements dans le modèle en utilisant le widget
ScopedModelDescendant
fourni par cette bibliothèque:
class CounterApp extends StatelessWidget { @override Widget build(BuildContext context) { return new ScopedModel<CounterModel>( model: new CounterModel(), child: new Column(children: [ new ScopedModelDescendant<CounterModel>( builder: (context, child, model) => new Text('${model.counter}'), ), new Text(" , CounterModel") ]) ); } }
Contrairement à l'utilisation de l'approche
setState()
, cette solution vous permet de séparer la logique d'affichage de la logique métier. Cependant, il impose certaines restrictions:
- Si le
Model
devient complexe, il devient alors difficile de déterminer quand utiliser la méthode notifyListeners()
et dans le cas contraire, pour éviter une mise à jour inutile de l'interface. - L'API fournie par
Model
, en général, ne décrit pas avec précision la nature asynchrone de l'interface d'application
Compte tenu de tout cela, si l'état de votre application n'est pas facile à gérer, je ne recommande pas d'utiliser cette approche de données. Je ne pense tout simplement pas qu'il est capable de fournir de manière productive la croissance et la complexité des applications.
Solution puissante - BLoC
Ce modèle a été inventé par Google et y est également utilisé. Il nous aidera à atteindre les objectifs suivants:
- Séparation de la logique d'affichage de la logique métier
- Utilisation de la nature asynchrone pour afficher une interface
- La possibilité de réutiliser dans différentes applications Dart, telles que Flutter ou AngularDart
L'idée derrière cette approche est très simple:
- BLoC utilise
Sink<T>
Api pour décrire la saisie asynchrone de nos composants de données - BLoC utilise
Stream<T>
Api pour décrire les données renvoyées de manière asynchrone par nos composants - Enfin, nous pouvons utiliser le widget
StreamBuilder
pour contrôler les flux de données, sans StreamBuilder
aucun effort de notre part pour vous abonner aux mises à jour des données et redessiner les widgets
Google a de bons exemples d'utilisation de ce modèle de gestion d'état, car il est largement utilisé et fortement recommandé par l'entreprise.
Je recommande moi-même fortement d'utiliser cette approche pour gérer l'état local, mais elle convient même pour gérer l'état global. Cependant, dans ce dernier cas, vous rencontrerez un problème - où et comment implémenter correctement BLoC afin que différents composants y aient accès, puis Redux entre en scène.
Redux et BLoC - le mix parfait pour moi
L'un des objectifs que j'ai décrits au début de l'article était de trouver quelque chose qui est largement utilisé et prévisible, et c'est Redux - un modèle et un ensemble d'outils qui ensemble nous aident à gérer l'état mondial. Il repose sur trois principes de base:
La seule source de vérité est que l'état entier de l'
state
votre application est stocké dans un objet arborescent dans un seul
store
- L'état est en lecture seule - la seule façon de changer l'état est d'appeler un objet d'action spécial qui décrit ce qui doit arriver à l'état
- Les modifications sont effectuées à l'aide de fonctions pures - pour déterminer les changements d'état, vous écrivez la fonction pure `
reducer
, qui ne devrait pas provoquer d'effets secondaires` Lien vers l'exemple de code`
Lien vers le message d'origine, d'où provient l'imageCette approche de la gestion de l'état est largement acceptée par les développeurs Web, et son apparition sur les appareils mobiles aidera à tirer parti des avantages des développeurs d'applications Web et mobiles.
Brian Egan développe à la fois le
Redux original et
flutter_redux , et il a également créé une
application Todo impressionnante dans laquelle il a appliqué de nombreux modèles architecturaux, y compris Redux.
Compte tenu de toutes les qualités de Redux, je recommande fortement de l'utiliser pour gérer l'état global, mais vous devez être sûr de ne pas l'utiliser pour gérer l'état local si vous souhaitez faire évoluer votre application.
Derniers mots
Il n'y a pas de solution complètement correcte ou incorrecte dans cet article. Pour décider de l'approche à appliquer dans votre projet, vous devez décider de vos besoins. Pour moi et mes objectifs, la combinaison de Redux et BLoC permet à mes projets de se développer rapidement et en toute sécurité, et facilite également l'entrée de ces projets par des développeurs tiers, grâce à des outils accessibles et clairs. Cependant, tout le monde n'a pas les mêmes besoins et au fil du temps, vous pouvez trouver à la fois des problèmes «dans les outils actuels» et des solutions encore meilleures. Il est très important de toujours rester curieux, d'apprendre et de penser si tel ou tel outil vous convient.