Architecture Flutter : Fournisseur vs BLoC

Publié: 2020-04-17

L'écriture d'applications avec Flutter crée de grandes opportunités pour choisir l'architecture. Comme souvent, la meilleure réponse à la question « Laquelle dois-je choisir ? c'est "Ça dépend". Lorsque vous obtenez cette réponse, vous pouvez être sûr d'avoir trouvé un expert en programmation.

Dans cet article, nous allons passer en revue les écrans les plus populaires dans les applications mobiles et les implémenter dans les deux architectures Flutter les plus populaires : Provider et BLoC . En conséquence, nous apprendrons les avantages et les inconvénients de chaque solution, ce qui nous aidera à choisir la bonne architecture Flutter pour notre prochain module ou application.

Brève introduction à l'architecture Flutter

Le choix de l'architecture pour un projet de développement Flutter est d'une grande importance, principalement en raison du fait que nous avons affaire à un paradigme de programmation déclarative moins couramment utilisé. Cela change complètement l'approche de la gestion de l'état que les développeurs natifs Android ou iOS connaissaient, en écrivant le code impérativement. Les données disponibles à un endroit de l'application ne sont pas si faciles à obtenir à un autre. Nous n'avons pas de références directes à d'autres vues dans l'arborescence, à partir desquelles nous pourrions obtenir leur état actuel.

Qu'est-ce que le fournisseur dans Flutter

Comme son nom l'indique, Provider est une architecture Flutter qui fournit le modèle de données actuel à l'endroit où nous en avons actuellement besoin. Il contient certaines données et avertit les observateurs lorsqu'un changement se produit. Dans Flutter SDK, ce type est appelé ChangeNotifier . Pour que l'objet de type ChangeNotifier soit disponible pour les autres widgets, nous avons besoin de ChangeNotifierProvider . Il fournit des objets observés pour tous ses descendants. L'objet qui est capable de recevoir les données actuelles est Consumer , qui a une instance ChangeNotifier dans le paramètre de sa fonction de construction qui peut être utilisée pour alimenter les vues suivantes avec des données.

Qu'est-ce que BLoC dans Flutter

Business Logic Components est une architecture Flutter beaucoup plus similaire aux solutions populaires en mobile telles que MVP ou MVVM. Il permet de séparer la couche de présentation des règles de logique métier. Il s'agit d'une application directe de l'approche déclarative sur laquelle Flutter insiste fortement, c'est-à-dire UI = f (état) . BLoC est un endroit où vont les événements de l'interface utilisateur. Au sein de cette couche, suite à l'application de règles métier à un événement donné, BLoC répond avec un état spécifique, qui revient ensuite à l'interface utilisateur. Lorsque la couche de vue reçoit un nouvel état, elle reconstruit sa vue en fonction de ce que l'état actuel exige.

Icône des services de développement

Intéressé par le développement de Flutter ?

Voir nos solutions

Comment créer une liste dans Flutter

Une liste déroulante est probablement l'une des vues les plus populaires dans les applications mobiles. Par conséquent, choisir la bonne architecture Flutter peut être crucial ici. Théoriquement, afficher la liste elle-même n'est pas difficile. La situation devient plus délicate lorsque, par exemple, nous ajoutons la possibilité d'effectuer une certaine action sur chaque élément. Cela devrait entraîner un changement à différents endroits de l'application. Dans notre liste, nous pourrons sélectionner chacun des éléments, et chacun de ceux sélectionnés sera affiché dans une liste séparée sur un écran différent.

Créer une liste dans Flutter

Par conséquent, nous devons stocker les éléments qui ont été sélectionnés, afin qu'ils puissent être affichés sur un nouvel écran. De plus, nous devrons reconstruire la vue à chaque fois que la case à cocher est cochée, pour afficher réellement cocher / décocher.

Le modèle d'élément de liste semble très simple :

 classe Médias Sociaux {
 identifiant int ;
 Titre de la chaîne ;
 Icône de chaîneAsset ;
 booléen estFavori ;

 Des médias sociaux(
     {@required this.id,
     @required this.title,
     @ requis this.iconAsset,
     this.isFavourite = false});

 void setFavorite(bool isFavourite) {
   this.isFavorite = isFavourite;
 }
}

Comment créer une liste avec le fournisseur

Dans le modèle de fournisseur, le modèle ci-dessus doit être stocké dans un objet. L'objet doit étendre le ChangeNotifier pour pouvoir accéder à SocialMedia à partir d'un autre endroit de l'application.

 la classe SocialMediaModel étend ChangeNotifier {
 final List<SocialMedia> _socialMedia = [ /* certains objets de médias sociaux */ ] ;

 UnmodifiableListView<SocialMedia> obtenir les favoris {
   return UnmodifiableListView(_socialMedia.where((item) => item.isFavourite));
 }

 UnmodifiableListView<SocialMedia> obtenir tous les {
   return UnmodifiableListView(_socialMedia);
 }


void setFavourite(int itemId, bool isChecked) {
 _des médias sociaux
     .firstWhere((item) => item.id == itemId)
     .setFavourite(isChecked);
 notifierListeners();
}

Toute modification de cet objet, qui nécessitera une reconstruction sur la vue, doit être signalée à l'aide de notifyListeners() . Dans le cas de la méthode setFavourite() pour demander à Flutter de restituer le fragment d'interface utilisateur, cela observera le changement dans cet objet.

Nous pouvons maintenant passer à la création de la liste. Pour remplir le ListView avec des éléments, nous devrons accéder à l'objet SocialMediaModel , qui stocke une liste de tous les éléments. Vous pouvez le faire de deux manières :

  • Provider.of<ModelType>(contexte, écoute : false)
  • Consommateur

Le premier fournit l'objet observé et permet de décider si l'action effectuée sur l'objet doit reconstruire le widget courant, en utilisant le paramètre listen . Ce comportement sera utile dans notre cas.

 class SocialMediaListScreen étend StatelessWidget {
 ÉcranListeMédiaSocial();

 @passer outre
 Génération de widget (contexte BuildContext) {
   var socialMedia = Provider.of<SocialMediaModel>(context, listen : false);

   retourne VueListe(
     enfants : socialMedia.all
         .map((item) => CheckboxSocialMediaItem(item : item))
         .lister(),
   );
 }
}

Nous avons besoin d'une liste de tous les médias sociaux, mais il n'est pas nécessaire de reconstruire toute la liste. Voyons à quoi ressemble le widget d'élément de liste.

 class CheckboxSocialMediaItem étend StatelessWidget {
 article final sur les réseaux sociaux ;

 CheckboxSocialMediaItem({Key key, @required this.item}) : super(key: key);

 @passer outre
 Génération de widget (contexte BuildContext) {
   rembourrage de retour(
     rembourrage : const EdgeInsets.all(Dimensions.paddingDefault),
     enfant : Ligne(
       enfants: [
         Consommateur<SocialMediaModel>(
           builder : (contexte, modèle, enfant) {
             retour Case à cocher(
               valeur : item.isFavourite,
               onChanged : (est coché) =>
                   model.setFavourite(item.id, isChecked),
             );
           },
         ),
         SocialMediaItem(
           article : article,
         )
       ],
     ),
   );
 }
}

Nous écoutons le changement de la valeur de la case à cocher et mettons à jour le modèle en fonction de l'état de la vérification. La valeur de la case à cocher elle-même est définie à l'aide de la propriété du modèle de données. Cela signifie qu'après la sélection, le modèle changera le champ isFavourite en true . Cependant, la vue ne présentera pas ce changement tant que nous n'aurons pas reconstruit la case à cocher. Ici, un objet Consumer est fourni avec de l'aide. Il fournit l'objet observé et reconstruit tous ses descendants après avoir reçu des informations sur la modification du modèle.

Il vaut la peine de placer Consumer uniquement là où il est nécessaire de mettre à jour le widget afin d'éviter des vues de reconstruction inutiles. Veuillez noter que si, par exemple, la sélection de la case à cocher déclenche une action supplémentaire comme changer le titre de l'élément, Consumer devra être déplacé plus haut dans l'arborescence des widgets, afin de devenir le parent du widget responsable de l'affichage du titre . Sinon, la vue du titre ne sera pas mise à jour.

La création d'un écran de médias sociaux préféré sera similaire. Nous obtiendrons une liste d'éléments favoris à l'aide de Provider .

 la classe FavoritesListScreen étend StatelessWidget {
 EcranListeFavoris();

 @passer outre
 Génération de widget (contexte BuildContext) {
   var list = Provider.of<SocialMediaModel>(contexte, écoute : false).favourites ;

   retourne VueListe(
     enfants : liste
         .map((item) => Remplissage(
             rembourrage : const EdgeInsets.all(Dimensions.paddingDefault),
             enfant : SocialMediaItem (élément : élément)))
         .lister(),
   );
 }
}

Lorsque la méthode de construction est appelée, le fournisseur renverra la liste actuelle des médias sociaux favoris.

Comment créer une liste avec BLoC

Dans notre application simple, nous avons jusqu'à présent deux écrans. Chacun d'eux aura son propre objet BLoC . Cependant, gardez à l'esprit que les éléments sélectionnés sur l'écran principal doivent apparaître sur la liste des médias sociaux favoris. Par conséquent, nous devons en quelque sorte transférer les événements de sélection de cases à cocher en dehors de l'écran. La solution consiste à créer un objet BLoC supplémentaire qui gérera les événements qui affectent l'état de nombreux écrans. Appelons-le BLoC global. Ensuite, les objets BLoC affectés à des écrans individuels écouteront les changements dans les états BLoC globaux et répondront en conséquence.

Avant de créer un objet BLoC , vous devez d'abord réfléchir aux événements que la vue pourra envoyer à la couche BLoC et aux états auxquels elle répondra. Dans le cas d'un BLoC global, les événements et les états seront les suivants :

 classe abstraite SocialMediaEvent {}

class CheckboxChecked étend SocialMediaEvent {
 booléen final isChecked ;
 ID d'élément final int ;

 CheckboxChecked(this.isChecked, this.itemId);
}


classe abstraite SocialMediaState {}

la classe ListPresented étend SocialMediaState {
 Liste finale<SocialMedia> liste ;

 ListPresented(this.list);
}

L'événement CheckboxChecked doit être dans le BLoC global, car il affectera l'état de nombreux écrans - pas un seul. En ce qui concerne les états, nous en avons un dans lequel la liste est prête à être affichée. Du point de vue global du BLoC , il n'est pas nécessaire de créer plus d'états. Les deux écrans doivent afficher la liste et les BLoC individuels dédiés à l'écran spécifique doivent s'en occuper. La mise en œuvre du BLoC global lui-même ressemblera à ceci :

 class SocialMediaBloc étend Bloc<SocialMediaEvent, SocialMediaState> {
 référentiel final SimpleSocialMediaRepository ;

 SocialMediaBloc(this.repository);

 @passer outre
 SocialMediaState get initialState => ListPresented(repository.getSocialMedia);

 @passer outre
 Flux<SocialMediaState> mapEventToState(événement SocialMediaEvent) async* {
   si (l'événement est CheckboxChecked) {
     rendement _mapCheckboxCheckedToState (événement);
   }
 }

 SocialMediaState _mapCheckboxCheckedToState (événement CheckboxChecked) {
   liste mise à jour finale = (état comme ListPresented).list;
   liste mise à jour
       .firstWhere((item) => item.id == event.itemId)
       .setFavourite(event.isChecked);
   return ListPresented (liste mise à jour);
 }
}

L'état initial est ListPresented - nous supposons que nous avons déjà reçu des données du référentiel. Nous n'avons besoin de répondre qu'à un seul événement : CheckboxChecked . Nous allons donc mettre à jour l'élément sélectionné à l'aide de la méthode setFavourite et envoyer la nouvelle liste enveloppée dans l'état ListPresented .

Nous devons maintenant envoyer l'événement CheckboxChecked lorsque nous tapons sur la case à cocher. Pour ce faire, nous aurons besoin d'une instance de SocialMediaBloc à un endroit où nous pourrons attacher le rappel onChanged . Nous pouvons obtenir cette instance en utilisant BlocProvider - elle ressemble à Provider à partir du modèle décrit ci-dessus. Pour qu'un tel BlocProvider fonctionne, plus haut dans l'arborescence des widgets, vous devez initialiser l'objet BLoC souhaité. Dans notre exemple, cela se fera dans la méthode main :

 void main() => runApp(BlocProvider(
   créer : (contexte) {
     return SocialMediaBloc(SimpleSocialMediaRepository());
   },
   enfant : ArchitecturesSampleApp()) );

Grâce à cela, dans le code de la liste principale, nous pouvons facilement appeler BLoC en utilisant BlocProvider.of() et lui envoyer un événement en utilisant la méthode add :

 class SocialMediaListScreen étend StatefulWidget {
 _SocialMediaListState createState() => _SocialMediaListState();
}

class _SocialMediaListState étend State<SocialMediaListScreen> {
 @passer outre
 Génération de widget (contexte BuildContext) {
   return BlocBuilder<SocialMediaListBloc, SocialMediaListState>(
     constructeur : (contexte, état) {
       si (l'état est MainListLoaded) {
         retourne VueListe(
           enfants : state.socialMedia
               .map((item) => Case à cocherSocialMediaItem(
                     article : article,
                     onCheckboxChanged : (isChecked) =>
                         BlocProvider.of<SocialMediaBloc>(contexte)
                             .add(CheckboxChecked(isChecked, item.id)),
                   ))
               .lister(),
         );
       } autre {
         return Center(child: Text(Strings.emptyList));
       }
     },
   );
 }
}

Nous avons déjà la propagation de l'événement CheckboxChecked vers BLoC , nous savons également comment BLoC répondra à un tel événement. Mais en fait… qu'est-ce qui entraînera la reconstruction de la liste avec la case déjà cochée ? Le BLoC global ne prend pas en charge la modification des états de liste, car il est géré par des objets BLoC individuels affectés aux écrans. La solution est l'écoute précédemment mentionnée d'un BLoC global pour changer l'état et répondre en fonction de cet état. Ci-dessous, le BLoC dédié à la liste principale des médias sociaux avec une case à cocher :

 classe SocialMediaListBloc
   étend Bloc<SocialMediaListEvent, SocialMediaListState> {
 bloc principal de SocialMediaBloc final ;

 SocialMediaListBloc({@required this.mainBloc}) {
   mainBloc.listen((état) {
     si (l'état est ListPresented) {
       add(ScreenStart(state.list));
     }
   });
 }

 @passer outre
 SocialMediaListState get initialState => MainListEmpty();

 @passer outre
 Flux<SocialMediaListState> mapEventToState(
     Événement SocialMediaListEvent) async* {
   switch (event.runtimeType) {
     cas ScreenStart :
       rendement MainListLoaded((event as ScreenStart).list);
       Pause;
   }
 }
}

Lorsque SocialMediaBloc renvoie l'état ListPresented , SocialMediaListBloc en est informé. Notez que ListPresented transmet une liste. C'est celui qui contient des informations mises à jour sur la vérification de l'élément avec la case à cocher.

De même, nous pouvons créer un BLoC dédié à l'écran des réseaux sociaux favoris :

 class FavorisListeBloc étend Bloc<FavoritesListEvent, FavorisListSate> {
 bloc principal de SocialMediaBloc final ;

 FavoritesListBloc({@required this.mainBloc}) {
   mainBloc.listen((état) {
     si (l'état est ListPresented) {
       add(FavoritesScreenStart(state.list));
     }
   });
 }

 @passer outre
 FavoritesListSate get initialState => FavoritesListEmpty();

 @passer outre
 Stream<FavouritesListSate> mapEventToState(événement FavoritesListEvent) async* {
   si (l'événement est FavoritesScreenStart) {
     var favouritesList = event.list.where((item) => item.isFavourite).toList();
     rendement FavoritesListLoaded(favouritesList);
   }
 }
}

La modification de l'état dans le BLoC global entraîne le déclenchement de l'événement FavoritesScreenStart avec la liste actuelle. Ensuite, les éléments marqués comme favoris sont filtrés et une telle liste s'affiche à l'écran.

Comment créer un formulaire avec de nombreux champs dans Flutter

Les formulaires longs peuvent être délicats, en particulier lorsque les exigences supposent différentes variantes de validation ou certains changements à l'écran après la saisie du texte. Sur l'écran d'exemple, nous avons un formulaire composé de plusieurs champs et du bouton "SUIVANT". Les champs seront automatiquement validés et le bouton désactivé jusqu'à ce que le formulaire soit entièrement valide. Après avoir cliqué sur le bouton, un nouvel écran s'ouvrira avec les données saisies dans le formulaire.

Nous devons valider chaque champ et vérifier l'ensemble de la correction du formulaire pour bien définir l'état du bouton. Ensuite, les données collectées devront être stockées pour l'écran suivant.

Créer un formulaire avec de nombreux champs dans Flutter

Comment créer un formulaire avec de nombreux champs avec Provider

Dans notre application, nous aurons besoin d'un deuxième ChangeNotifier , dédié aux écrans d'informations personnelles. Nous pouvons donc utiliser le MultiProvider , où nous fournissons une liste d'objets ChangeNotifier . Ils seront disponibles pour tous les descendants de MultiProvider .

 class ArchitecturesSampleApp étend StatelessWidget {
 référentiel final SimpleSocialMediaRepository ;

 ArchitecturesSampleApp({Key key, this.repository}) : super(key: key);

 @passer outre
 Génération de widget (contexte BuildContext) {
   return MultiProvider(
     fournisseurs: [
       ChangeNotifierProvider<SocialMediaModel>(
         créer : (contexte) => SocialMediaModel (référentiel),
       ),
       ChangeNotifierProvider<PersonalDataNotifier>(
         créer : (contexte) => PersonalDataNotifier(),
       )
     ],
     enfant : MaterialApp(
       titre : Strings.architecturesSampleApp,
       debugShowCheckedModeBanner : faux,
       accueil : StartScreen(),
       routes : <Chaîne, WidgetBuilder>{
         Routes.socialMedia : (contexte) => SocialMediaScreen(),
         Routes.favourites : (contexte) => ÉcranFavoris(),
         Routes.personalDataForm : (contexte) => PersonalDataScreen(),
         Routes.personalDataInfo : (contexte) => PersonalDataInfoScreen()
       },
     ),
   );
 }
}

Dans ce cas, PersonalDataNotifier agira comme une couche de logique métier - il validera les champs, aura accès au modèle de données pour sa mise à jour et mettra à jour les champs dont dépendra la vue.

Le formulaire lui-même est une très belle API de Flutter, où nous pouvons attacher automatiquement des validations à l'aide du validateur de propriété et enregistrer les données du formulaire dans le modèle à l'aide du rappel onSaved . Nous déléguerons les règles de validation à PersonalDataNotifier et lorsque le formulaire sera correct, nous lui transmettrons les données saisies.

La chose la plus importante sur cet écran sera d'écouter un changement dans chaque champ et d'activer ou de désactiver le bouton, en fonction du résultat de la validation. Nous utiliserons le rappel onChange de l'objet Form . Dans celui-ci, nous allons d'abord vérifier le statut de validation, puis le transmettre à PersonalDataNotifier .

 Formulaire(
 clé : _formKey,
 validation automatique : vrai,
 onChanged : () => _onFormChanged(personalDataNotifier),
 enfant:

void _onFormChanged(PersonalDataNotifier personalDataNotifier) ​​{
 var isValid = _formKey.currentState.validate();
 personalDataNotifier.onFormChanged(isValid);
}

Dans PersonalDataNotifier , nous allons préparer la variable isFormValid . Nous allons le modifier (n'oubliez pas d'appeler notifyListeners() ) et dans la vue, nous allons changer l'état du bouton en fonction de sa valeur. N'oubliez pas d'obtenir l'instance de Notifier avec le paramètre listen : true - sinon, notre vue ne se reconstruira pas et l'état du bouton restera inchangé.

 var personalDataNotifier = Provider.of<PersonalDataNotifier>(context, listen : true);

En fait, étant donné que nous utilisons personalDataNotifier à d'autres endroits, où le rechargement de la vue n'est pas nécessaire, la ligne ci-dessus n'est pas optimale et devrait avoir le paramètre listen défini sur false . La seule chose que nous voulons recharger est le bouton, nous pouvons donc l'envelopper dans un Consumer classique :

 Consommateur<PersonalDataNotifier>(
 constructeur : (contexte, notificateur, enfant) {
   return RisedButton(
     enfant : Texte(Strings.addressNext),
     onPressed : notifier.isFormValid
         ? /* action lorsque le bouton est activé */
         : nul,
     couleur: Couleurs.bleu,
     disabledColor : Colors.grey,
   );
 },
)

Grâce à cela, nous ne forçons pas les autres composants à se recharger à chaque fois que nous utilisons un notificateur.

Dans la vue affichant les données personnelles, il n'y aura plus de problèmes - nous avons accès à PersonalDataNotifier et à partir de là, nous pouvons télécharger le modèle mis à jour.

Comment créer un formulaire avec de nombreux champs avec BLoC

Pour l'écran précédent, nous avions besoin de deux objets BLoC . Ainsi, lorsque nous ajouterons un autre "double écran", nous en aurons quatre en tout. Comme dans le cas de Provider , nous pouvons le gérer avec MultiBlocProvider , qui fonctionne presque à l'identique.

 void main() => runApp(
     MultiBlocProvider(fournisseurs : [
       FournisseurBloc(
         créer : (contexte) => SocialMediaBloc(SimpleSocialMediaRepository()),
       ),
       FournisseurBloc(
           créer : (contexte) => SocialMediaListBloc(
               mainBloc : BlocProvider.of<SocialMediaBloc>(contexte))),
       FournisseurBloc(
         créer : (contexte) => PersonalDataBloc(),
       ),
       FournisseurBloc(
         créer : (contexte) => PersonalDataInfoBloc(
             mainBloc : BlocProvider.of<PersonalDataBloc>(contexte)),
       )
     ], enfant : ArchitecturesSampleApp()),
   );

Comme dans le modèle BLoC , il est préférable de commencer par les états et actions possibles.

 classe abstraite PersonalDataState {}

la classe NextButtonDisabled étend PersonalDataState {}

la classe NextButtonEnabled étend PersonalDataState {}

la classe InputFormCorrect étend PersonalDataState {
 modèle final de données personnelles ;

 InputFormCorrect(this.model);
}

Ce qui change sur cet écran, c'est l'état du bouton. Nous avons donc besoin d'États séparés pour cela. De plus, l'état InputFormCorrect nous permettra d'envoyer les données que le formulaire a collectées.

 classe abstraite PersonalDataEvent {}

class FormInputChanged étend PersonalDataEvent {
 booléen final isValid ;
 FormInputChanged(this.isValid);
}

class FormCorrect étend PersonalDataEvent {
 formulaireDonnées personnelles finale ;

 FormCorrect(this.formData);
}

L'écoute des changements dans le formulaire est cruciale, d'où l'événement FormInputChanged . Lorsque le formulaire est correct, l'événement FormCorrect est envoyé.

En ce qui concerne les validations, il y a une grande différence ici si vous le comparez à Provider. Si nous voulions enfermer toute la logique de validation dans la couche BLoC , nous aurions beaucoup d'événements pour chacun des champs. De plus, de nombreux états exigeraient que la vue affiche les messages de validation.

C'est bien sûr possible, mais ce serait comme un combat contre l'API TextFormField au lieu d'utiliser ses avantages. Par conséquent, s'il n'y a pas de raisons claires, vous pouvez laisser des validations dans la couche de vue.

L'état du bouton dépendra de l'état envoyé à la vue par BLoC :

 BlocBuilder<BlocDonnéesPersonnelles, ÉtatDonnéesPersonnelles>(
   constructeur : (contexte, état) {
 return RisedButton(
   enfant : Texte(Strings.addressNext),
   onPressed : l'état est NextButtonEnabled
       ? /* action lorsque le bouton est activé */
       : nul,
   couleur: Couleurs.bleu,
   disabledColor : Colors.grey,
 );
})

La gestion des événements et le mappage aux états dans PersonalDataBloc seront les suivants :

 @passer outre
Stream<PersonalDataState> mapEventToState (événement PersonalDataEvent) async* {
 si (l'événement est FormCorrect) {
   rendement InputFormCorrect(event.formData);
 } sinon si (l'événement est FormInputChanged) {
   rendement mapFormInputChangedToState (événement);
 }
}

PersonalDataState mapFormInputChangedToState (événement FormInputChanged) {
 if (event.isValid) {
   return NextButtonEnabled();
 } autre {
   return NextButtonDisabled();
 }
}

Quant à l'écran avec un résumé des données personnelles, la situation est similaire à l'exemple précédent. Le BLoC attaché à cet écran récupérera les informations du modèle à partir du BLoC de l'écran du formulaire.

 classe PersonalDataInfoBloc
   étend Bloc<PersonalDataInfoEvent, PersonalDataInfoState> {
 final PersonalDataBloc mainBloc ;

 PersonalDataInfoBloc({@required this.mainBloc}) {
   mainBloc.listen((état) {
     si (l'état est InputFormCorrect) {
       add(PersonalDataInfoScreenStart(state.model));
     }
   });
 }

 @passer outre
 PersonalDataInfoState get initialState => InfoEmpty();

 @passer outre
 Flux<PersonalDataInfoState> mapEventToState (événement PersonalDataInfoEvent) async* {
   si (l'événement est PersonalDataInfoScreenStart) {
     rendement InfoLoaded(event.model);
   }
 }
}

Architecture Flutter : notes à retenir

Les exemples ci-dessus suffisent à montrer qu'il existe de nettes différences entre les deux architectures. BLoC sépare très bien la couche de vue de la logique métier. Cela implique une meilleure réutilisabilité et testabilité. Il semble que pour gérer des cas simples, vous deviez écrire plus de code que dans Provider . Comme vous le savez, dans ce cas, cette architecture Flutter deviendra plus utile à mesure que la complexité de l'application augmentera.

Icône à emporter

Vous souhaitez créer une application tournée vers l'avenir pour votre entreprise ?

Prenons contact

Le fournisseur sépare également bien l'interface utilisateur de la logique et ne force pas la création d'états séparés avec chaque interaction de l'utilisateur, ce qui signifie que souvent vous n'avez pas à écrire une grande quantité de code pour gérer un cas simple. Mais cela peut causer des problèmes dans des cas plus complexes.

Cliquez ici pour découvrir l'intégralité du projet.