web-dev-qa-db-fra.com

Bloc, flottement et navigation

Donc, comme la plupart, je suis nouveau sur Bloc et flutter et Dart et j'enveloppe ma tête. J'ai googlé, parcouru les messages ici mais je n'ai pas vraiment trouvé de réponses.

Il s'agit donc de navigation avec bloc et flottement. Prenons l'exemple d'une connexion. Il y a donc une page de connexion avec un bloc derrière et à un moment donné, quelqu'un appuie sur un bouton pour se connecter.

Nous pouvons donc appeler une fonction dans le bloc qui effectue la validation. Je pense que c'est contre l'approche stricte mais je vois des gens faire ça. Mais si la connexion réussit, comment accédez-vous à l'écran suivant? Vous n'êtes pas censé naviguer dans un bloc?

Mais si cette page de connexion utilise un StreamBuilder pour changer d'état, vous ne pouvez pas non plus ajouter une navigation dans un générateur? Vous ne pouvez pas retourner la navigation, vous renvoyez des widgets.

L'inststate est un endroit où vous pouvez naviguer, mais pouvez-vous avoir un générateur de flux dans un initstate qui écoute les changements d'état dans le bloc?

C'est un peu déroutant en ce moment mais je persévère car c'est supposé pour être la voie à suivre ...

merci Paul

25
paulinventome

Pour que le mythe du BLoC soit le aller de l'avant: il n'y a pas de moyen parfait pour gérer l'état. Chaque architecture de gestion d'état résout certains problèmes mieux que d'autres; il y a toujours des compromis et il est important d'en être conscient lors du choix d'une architecture.

Généralement, une bonne architecture est pratique : elle est évolutive et extensible tout en ne nécessitant qu'une surcharge minimale. Parce que les opinions des gens sur la praticabilité diffèrent, l'architecture implique toujours une opinion, alors prenez ce qui suit avec un grain de sel car je vais exposer mon point de vue personnel sur la façon d'adopter BLoC pour votre application.

BLoC est une approche très prometteuse pour la gestion de l'État à Flutter en raison d'un ingrédient de signature: les flux. Ils permettent de découpler l'interface utilisateur de la logique métier et ils fonctionnent bien avec l'approche Flutter-ish de reconstruction de sous-arborescences de widgets entiers une fois obsolètes. Alors naturellement, chaque communication depuis et vers le BLoC devrait utiliser des flux, non?

+----+  Stream   +------+
| UI | --------> | BLoC |
|    | <-------- |      |
+----+   Stream  +------+

Bon type de.

La chose importante à retenir est que l'architecture de gestion d'état est un moyen pour une fin ; vous ne devez pas simplement faire des choses pour le plaisir, mais garder l'esprit ouvert et évaluer soigneusement les avantages et les inconvénients de chaque option. La raison pour laquelle nous séparons le BLoC de l'interface utilisateur est que le BLoC n'a pas besoin de se soucier de la façon dont l'interface utilisateur est structurée - il fournit simplement de jolis flux simples et tout ce qui se passe avec les données est la responsabilité de l'interface utilisateur.

Mais alors que les flux se sont révélés être un moyen fantastique de transporter des informations du BLoC à l'interface utilisateur, ils ajoutent des frais généraux inutiles dans l'autre sens: les flux ont été conçus pour transporter des flux de données continus (c'est même dans le nom), mais la plupart des temps, l'interface utilisateur doit simplement déclencher des événements uniques dans le BLoC. C'est pourquoi, parfois, vous voyez des Stream<void> S ou des solutions similaires de piratage¹, juste pour adhérer à la manière strictement BLoC-y de faire les choses.

De plus, si nous poussions de nouvelles routes basées sur le flux du BLoC, le BLoC contrôlerait essentiellement le flux de l'interface utilisateur - mais avoir un code qui contrôle directement à la fois l'interface utilisateur et la logique métier est exactement ce que nous avons essayé d'empêcher!

C'est pourquoi certains développeurs (dont moi) rompent simplement avec la solution entièrement basée sur les flux et adoptent une manière personnalisée de déclencher des événements dans le BLoC à partir de l'interface utilisateur. Personnellement, j'utilise simplement des appels de méthode (qui retournent généralement Futures) pour déclencher les événements du BLoC:

+----+   method calls    +------+
| UI | ----------------> | BLoC |
|    | <---------------- |      |
+----+   Stream, Future  +------+

Ici, le BLoC renvoie Streams pour les données "en direct" et Futures comme réponses aux appels de méthode.

Voyons comment cela pourrait fonctionner pour votre exemple:

  • Le BLoC peut fournir un Stream<bool> Indiquant si l'utilisateur est connecté, ou même un Stream<Account>, Où Account contient les informations de compte de l'utilisateur.
  • Le BLoC peut également fournir une méthode asynchrone Future<void> signIn(String username, String password) qui ne renvoie rien si la connexion a réussi ou renvoie une erreur dans le cas contraire.
  • L'interface utilisateur peut gérer la gestion des entrées seule et déclencher quelque chose comme ce qui suit une fois que le bouton de connexion est enfoncé:
try {
  setState(() => _isLoading = true); // This could display a loading spinner of sorts.
  await Bloc.of(context).signIn(_usernameController.text, _passwordController.text);
  Navigator.of(context).pushReplacement(...); // Push logged in screen.
} catch (e) {
  setState(() => _isLoading = false);
  // TODO: Display the error on the screen.
}

De cette façon, vous obtenez une belle séparation des préoccupations:

  • Le BLoC fait vraiment ce qu'il est censé faire: gérer la logique métier (dans ce cas, connecter l'utilisateur).
  • L'interface utilisateur se soucie simplement de deux choses:
    • Affichage des données utilisateur à partir de Streams et
    • réagir aux actions des utilisateurs en les déclenchant dans le BLoC et en effectuant des actions d'interface utilisateur en fonction du résultat.²

Enfin, je tiens à souligner qu'il ne s'agit que d'une seule solution possible qui a évolué au fil du temps en essayant différentes manières de gérer l'état dans une application complexe. Il est important de connaître différents points de vue sur le fonctionnement de la gestion des états, je vous encourage donc à approfondir ce sujet, peut-être en regardant la session "" Pragmatic State Management in Flutter " de Google I/O.

[~ # ~] edit [~ # ~] : Je viens de trouver cette architecture dans exemples d'architecture de Brian Egan , où elle s'appelle "BLoC simple". Si vous voulez connaître différentes architectures, je vous recommande vraiment de jeter un œil au dépôt.


¹ Cela devient encore plus laid lorsque vous essayez de fournir plusieurs arguments à une action BLoC - car alors vous auriez besoin de définir une classe wrapper juste pour la transmettre au Stream.

² I do admets que cela devient un peu moche au démarrage de l'application: vous aurez besoin d'une sorte d'écran de démarrage qui vérifie simplement le flux du BLoC et redirige l'utilisateur vers l'écran approprié selon que il/elle s'est connecté ou non. Cette exception à la règle se produit parce que l'utilisateur a effectué une action - démarrer l'application - mais le cadre Flutter ne nous permet pas directement de nous y connecter (du moins pas avec élégance, pour autant que je sache).

21
Marcel

BlocListener est le widget dont vous avez probablement besoin. Si l'état passe à (par exemple) LoginSuccess, l'écouteur de bloc peut alors appeler l'habituelle Navigate.of(context). l'exemple montre ici le BlocListener en action , mais au lieu de naviguer, il affiche une Snackbar.

Une autre option consiste à passer un rappel dans l'événement.

 BlocProvider.of<MyBloc>(context).add(MyEvent(
              data: data,
              onSuccess: () {
                Navigator.Push(
                  context,
                  MaterialPageRoute(builder: (context) {
                    return HomePage();
                  }),
                );
              }));
2
34m0