Πώς να χειριστείτε την κατάσταση στο Flutter χρησιμοποιώντας το μοτίβο BLoC

Πέρυσι, πήρα το Flutter και πρέπει να πω ότι ήταν ένα φοβερό ταξίδι μέχρι στιγμής. Το Flutter είναι το εκπληκτικό πλαίσιο της Google για τη δημιουργία εφαρμογών υψηλής ποιότητας για Android και iOS.

Όπως με την κατασκευή σχεδόν οποιασδήποτε εφαρμογής, υπάρχει πάντα η ανάγκη χειρισμού της κατάστασης εφαρμογής. Είναι σημαντικό η διαχείριση του κράτους να γίνεται αποτελεσματικά, ώστε να αποφευχθεί η δημιουργία τεχνικού χρέους, ειδικά καθώς η αίτησή σας μεγαλώνει και γίνεται πιο περίπλοκη.

Στο Flutter, όλα τα στοιχεία UI είναι widget. Καθώς αρχίζετε να συνθέτετε αυτά τα γραφικά στοιχεία για να δημιουργήσετε την καταπληκτική εφαρμογή σας, θα καταλήξετε με ένα δέντρο με πολύ ένθετα widget. Αυτά τα widgets πιθανότατα θα πρέπει να μοιράζονται την κατάσταση της εφαρμογής μεταξύ τους.

Σε αυτό το άρθρο, θα δούμε πώς να χειριστούμε την κατάσταση στο Flutter χρησιμοποιώντας το μοτίβο BLoC.

Η διαχείριση της κατάστασης στο Flutter μπορεί να επιτευχθεί με διάφορους τρόπους:

Κληρονομικό Widget : Σας επιτρέπει να διαδίδετε δεδομένα στα θυγατρικά widgets και τα widget ξαναχτίζονται κάθε φορά που υπάρχει αλλαγή στην κατάσταση της εφαρμογής. Το μειονέκτημα της χρήσης της κλάσης βάσης InheritedWidget είναι ότι η κατάστασή σας είναι οριστική και αυτό δημιουργεί πρόβλημα εάν θέλετε να μεταλλάξετε την κατάστασή σας.

Scoped Model : Πρόκειται για ένα εξωτερικό πακέτο που έχει δημιουργηθεί πάνω από το InheritedWidget και προσφέρει έναν ελαφρώς καλύτερο τρόπο πρόσβασης, ενημέρωσης και μετάλλαξης κατάστασης. Σας επιτρέπει να μεταφέρετε εύκολα ένα μοντέλο δεδομένων από ένα γονικό Widget στους απογόνους του. Επιπλέον, ανακατασκευάζει όλα τα παιδιά που χρησιμοποιούν το μοντέλο όταν ενημερώνεται το μοντέλο.

Αυτό μπορεί να δημιουργήσει ένα πρόβλημα απόδοσης, ανάλογα με τον αριθμό των ScopedModelDescendants που έχει ένα μοντέλο, καθώς ξαναχτίζονται όταν υπάρχει ενημέρωση.

Αυτό το ζήτημα μπορεί να επιλυθεί αποσυνθέτοντας το ScopedModel σε πολλαπλά μοντέλα, ώστε να έχετε λεπτότερες εξαρτήσεις. Η ρύθμιση της rebuildOnChangeσημαίας θα falseεπιδιορθώσει επίσης αυτό το ζήτημα, αλλά φέρνει μαζί του το γνωστικό φορτίο να αποφασίζει ποιο widget θα πρέπει να ξαναχτιστεί ή όχι.

Redux : Ναι! Όπως και με το React, υπάρχει ένα πακέτο Redux που σας βοηθά να δημιουργήσετε και να καταναλώσετε εύκολα ένα κατάστημα Redux στο Flutter. Όπως και τον ομόλογό του JavaScript, υπάρχει συνήθως μερικές γραμμές κώδικα στερεότυπο και το ταξίδι μετ 'επιστροφής των δράσεων και μειωτήρες .

Εισαγάγετε το μοτίβο BLoC

Το μοτίβο Business Logic Component (BLoC) είναι ένα μοτίβο που δημιουργήθηκε από την Google και ανακοινώθηκε στο Google I / O '18. Το μοτίβο BLoC χρησιμοποιεί Reactive Programming για να χειριστεί τη ροή δεδομένων μέσα σε μια εφαρμογή.

Ένα BLoC στέκεται ως μεσάζων μεταξύ μιας πηγής δεδομένων στην εφαρμογή σας (π.χ. μια απόκριση API) και των widget που χρειάζονται τα δεδομένα. Λαμβάνει ροές συμβάντων / δεδομένων από την πηγή, χειρίζεται οποιαδήποτε απαιτούμενη επιχειρηματική λογική και δημοσιεύει ροές αλλαγών δεδομένων σε widget που ενδιαφέρονται για αυτά.

Το BLoC έχει δύο απλά συστατικά: νεροχύτες και ροές , και οι δύο παρέχονται από ένα StreamController . Προσθέτετε ροές συμβάντων / δεδομένων εισόδου σε ένα νεροχύτη και τις ακούτε ως ροές εξόδου δεδομένων μέσω ροής .

Ένα StreamController είναι προσβάσιμο μέσω της ‘dart:async’βιβλιοθήκης ή ως PublishSubject , ReplaySubject ή BehaviourSubject μέσω του rxdartπακέτου.

Ακολουθεί ένα απόσπασμα κώδικα που δείχνει ένα απλό BLoC:

import 'dart:async'; // import 'package:rxdart/rxdart.dart'; if you want to make use of PublishSubject, ReplaySubject or BehaviourSubject. // make sure you have rxdart: as a dependency in your pubspec.yaml file to use the above import class CounterBloc { final counterController = StreamController(); // create a StreamController or // final counterController = PublishSubject() or any other rxdart option; Stream get getCount => counterController.stream; // create a getter for our Stream // the rxdart stream controllers returns an Observable instead of a Stream void updateCount() { counterController.sink.add(data); // add whatever data we want into the Sink } void dispose() { counterController.close(); // close our StreamController to avoid memory leak } } final bloc = CounterBloc(); // create an instance of the counter bloc //======= end of CounterBloc file //======= somewhere else in our app import 'counter_bloc.dart'; // import the counter bloc file here @override void dispose() { bloc.dispose(); // call the dispose method to close our StreamController super.dispose(); } ... @override Widget build(BuildContext context) { return StreamBuilder( // Wrap our widget with a StreamBuilder stream: bloc.getCount, // pass our Stream getter here initialData: 0, // provide an initial data builder: (context, snapshot) => Text('${snapshot.data}'), // access the data in our Stream here ); } ...

Το BLoC είναι μια απλή τάξη Dart. Στο απόσπασμα κώδικα παραπάνω, δημιουργήσαμε μια CounterBlocτάξη και σε αυτήν, την StreamControllerοποία ονομάσαμε counterController. Δημιουργήσαμε ένα getter για το Stream που ονομάζεται getCount, μια updateCountμέθοδο που προσθέτει δεδομένα στο Sink όταν καλείται και μια disposeμέθοδο για το κλείσιμο του StreamController.

Για να αποκτήσετε πρόσβαση στα δεδομένα στη ροή μας, δημιουργήσαμε ένα StreamBuilderwidget και μεταβιβάσαμε τη ροή στην streamιδιοκτησία του και αποκτήσαμε πρόσβαση στα δεδομένα στη builderλειτουργία του.

Εφαρμογή BLoC

Θα μετατρέψουμε την προεπιλεγμένη εφαρμογή δείγματος Flutter σε BLOC. Ας προχωρήσουμε και δημιουργήστε μια νέα εφαρμογή Flutter. Στο τερματικό σας εκτελέστε την ακόλουθη εντολή:

$ flutter create bloc_counter && cd bloc_counter

Ανοίξτε την εφαρμογή στο αγαπημένο σας επεξεργαστή κειμένου και να δημιουργήσει τρία αρχεία στο φάκελο lib: counter.dart, counter_provider.dartκαι counter_bloc.dart.

Το CounterProviderδικό μας θα περιέχει έναν ακέραιο και μια μέθοδο για την αύξηση του. Προσθέστε τον ακόλουθο κώδικα στο counter_provider.dartαρχείο:

class CounterProvider { int count = 0; void increaseCount() => count++; }

Στη συνέχεια, θα εφαρμόσουμε τον μετρητή BLoC. Προσθέστε τον παρακάτω κώδικα στο counter_block.dartαρχείο σας :

Στην CounterBlocτάξη μας , χρησιμοποιήσαμε μέρος του αρχικού δείγματος κώδικα παραπάνω. Στη γραμμή 7, θεσμοθετήσαμε την CounterProviderτάξη μας και στη updateCountμέθοδο, καλέσαμε τη μέθοδο παροχέα να αυξήσει την καταμέτρηση και στη συνέχεια στη γραμμή 13, περάσαμε τον αριθμό στο νεροχύτη μας.

Αντικαταστήστε τον κωδικό στο main.dartαρχείο σας με τον παρακάτω κώδικα. Στον παρακάτω κώδικα, απλώς καταργήσαμε το μεγαλύτερο μέρος του προεπιλεγμένου αντίθετου κώδικα, τον οποίο θα μεταφέρουμε στο counter.dartαρχείο μας . Κάθε φορά incrementCounterπου καλείται η μέθοδος, καλούμε τη updateCountμέθοδο BLoC που ενημερώνει το πλήθος και την προσθέτει στο νεροχύτη μας.

Τώρα, το BLoC λαμβάνει και μεταδίδει δεδομένα. Μπορούμε να αποκτήσουμε πρόσβαση σε αυτά τα δεδομένα και να τα εμφανίσουμε σε μια οθόνη μέσω ενός StreamBuilder . Περιτυλίγουμε οποιοδήποτε widget που χρειάζεται τα δεδομένα σε ένα widget StreamBuilder και μεταβιβάζουμε τη ροή που περιέχει τα δεδομένα σε αυτό. Προσθέστε τον ακόλουθο κώδικα στο counter.dartαρχείο:

Στον παραπάνω κωδικό, διαθέτουμε ένα widget. Στην τάξη πολιτείας μας, στη γραμμή 13, καλούμε τη μέθοδο διάθεσης του μπλοκ, έτσι ώστε ο ελεγκτής ροής να μπορεί να κλείνει κάθε φορά που το widget αφαιρείται από το δέντρο.

Στη γραμμή 19, επιστρέφουμε ένα widget StreamBuilder και τη γραμμή 20, περνάμε το λήμμα για τη ροή μας σε αυτό και επίσης τα αρχικά δεδομένα στη γραμμή 21. Το StreamBuilder έχει επίσης ένα builderπου μας δίνει πρόσβαση στα δεδομένα μέσω a snapshot. Στη γραμμή 30, έχουμε πρόσβαση και εμφανίζουμε τα δεδομένα στο στιγμιότυπο.

Προχωρήστε και εκτελέστε την εφαρμογή εκτελώντας την παρακάτω εντολή. Βεβαιωθείτε ότι έχετε έναν εξομοιωτή σε λειτουργία.

$ flutter run

Με την εφαρμογή σας να λειτουργεί, κάντε κλικ στο εικονίδιο συν και παρακολουθήστε την αύξηση του μετρητή με κάθε κλικ.

Μαζί, καταφέραμε να εφαρμόσουμε την απλούστερη μορφή BLoC στο Flutter. Η ιδέα παραμένει η ίδια ανεξάρτητα από την περίπτωση χρήσης σας.

Ελπίζω να βρείτε αυτό το άρθρο χρήσιμο. Κάντε και μοιραστείτε, ώστε άλλοι να βρουν αυτό το άρθρο. Χτυπήστε με στο Twitter @developia_ με ερωτήσεις ή για συνομιλία.