Hallo Habr!
Lassen Sie mich Ihnen helfen, eine State-Management-Lösung für Ihre App zu verstehen und auszuwählen , die mir aufgefallen ist und mich für den Prozess des Lernens der Grundlagen des State-Managements in Flutter interessiert hat. Ich freue mich über jede Kritik zu dieser Übersetzung. In Backquotes (``) werden meine persönlichen Gedanken und Erklärungen geschrieben.

Flatter State Management ist ein heißes Thema. Es gibt viele mögliche Lösungen für das Problem, und die Auswahl der für Ihre Bedürfnisse am besten geeigneten Lösung ist äußerst einfach. Ich selbst war verwirrt, fand aber eine geeignete Lösung. Lass es mich mit dir teilen.
Um eine Lösung zu finden, die Ihren Anforderungen entspricht, müssen Sie die Anforderungen selbst ermitteln. In meinem Fall ist dies:
- Sie haben die Möglichkeit, das Projekt zu entwickeln, ohne die Qualität des Codes zu beeinträchtigen
- Trennen Sie die Anzeigelogik von der Geschäftslogik
- Haben Sie klaren Code, der schwer zu brechen ist
- Vorhersehbarkeit und Verständlichkeit des Codes
Angesichts dieser Anforderungen bleiben geeignete Optionen:
- Verwenden der
setState()
und Stateful Widgets - `Library` ScopedModel
- Verwenden des BLoC-Musters (Business Logic-Komponenten)
- Redux
Der Unterschied zwischen lokalem und globalem Zustand
Bevor Sie sich mit der Analyse ausgewählter Lösungen befassen, müssen Sie den Unterschied zwischen lokalem und globalem Zustand verstehen. Ein praktisches Beispiel ist dafür geeignet:
Stellen Sie sich ein Autorisierungsformular vor, in dem der Benutzer aufgefordert wird, einen Benutzernamen und ein Kennwort einzugeben und nach dem Senden des Formulars das Objekt "Benutzeridentität" abzurufen. In diesem Beispiel ist jede Überprüfung der in die Formularfelder eingegebenen Daten Teil des lokalen Status des "Autorisierungsformular-Widgets", und der Rest der Anwendung sollte dies nicht wissen. Das vom "Autorisierungsserver" zurückgegebene "Identitäts" -Objekt ist Teil des globalen Status. Andere Komponenten hängen also von diesem Objekt ab und ändern das Verhalten abhängig davon, ob der Benutzer autorisiert ist.
Kurze Schlussfolgerungen für diejenigen, die es satt haben zu wartenWenn Sie nicht warten möchten oder nicht an meiner Forschung interessiert sind, finden Sie hier einen kurzen Überblick über die Ergebnisse:

Ich empfehle, BLoC für die lokale Statusverwaltung und Redux für den globalen Status zu verwenden, insbesondere wenn Sie eine komplexe Anwendung erstellen, die mit der Zeit wächst.
Warum sollten Sie setState () nicht verwenden?
Die Verwendung von
setState()
in Ihren Widgets ist
setState()
um schnell Prototypen zu
setState()
und Feedback zu diesen Änderungen zu erhalten. Auf diese Weise können wir unsere Ziele jedoch nicht erreichen, da die Anzeigelogik mit der Geschäftslogik gemischt wird, was gegen das Prinzip der Sauberkeit und Qualität des Codes verstößt. Die Wartung eines solchen Codes wird in Zukunft schwierig sein. Daher wird dieser Ansatz, abgesehen von der Erstellung von Prototypen, nicht empfohlen.
ScopedModel - ein Schritt in die richtige Richtung
ScopedModel ist eine Drittanbieter-Bibliothek von
Brian Egan . Es ermöglicht das Erstellen spezieller
Models
Objekte sowie die Verwendung der
notifyListeners()
-Methode,
notifyListeners()
erforderlich. So verfolgen Sie beispielsweise Änderungen an den Eigenschaften eines Modellobjekts:
class CounterModel extends Model { int _counter = 0; int get counter = _counter; void increment() { _counter++; notifyListeners(); } }
In unseren Widgets können wir mit dem von dieser Bibliothek bereitgestellten
ScopedModelDescendant
Widget auf Änderungen im Modell reagieren:
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") ]) ); } }
Im Gegensatz zur Verwendung des
setState()
-Ansatzes können Sie mit dieser Lösung die Anzeigelogik von der Geschäftslogik trennen. Es gibt jedoch bestimmte Einschränkungen:
- Wenn das
Model
komplex wird, ist es schwierig zu bestimmen, wann die notifyListeners()
-Methode verwendet werden soll und wann eine unnötige Schnittstellenaktualisierung nicht notifyListeners()
werden soll. - Die von
Model
bereitgestellte API beschreibt im Allgemeinen die asynchrone Natur der Anwendungsschnittstelle nicht genau
In Anbetracht dessen empfehle ich die Verwendung dieses Datenansatzes nicht, wenn der Status Ihrer Anwendung nicht einfach zu verwalten ist. Ich glaube einfach nicht, dass er in der Lage ist, das Wachstum und die Komplexität von Anwendungen produktiv bereitzustellen.
Leistungsstarke Lösung - BLoC
Dieses Muster wurde von Google erfunden und wird auch dort verwendet. Er wird uns helfen, die folgenden Ziele zu erreichen:
- Trennung der Anzeigelogik von der Geschäftslogik
- Verwenden der asynchronen Natur zum Anzeigen einer Schnittstelle
- Die Möglichkeit zur Wiederverwendung in verschiedenen Dart-Anwendungen wie Flutter oder AngularDart
Die Idee hinter diesem Ansatz ist sehr einfach:
- BLoC verwendet
Sink<T>
API zur asynchronen Eingabe unserer Datenkomponenten - BLoC verwendet
Stream<T>
API zur Beschreibung der von unseren Komponenten asynchron zurückgegebenen Daten - Schließlich können wir das
StreamBuilder
Widget verwenden, um den StreamBuilder
zu steuern, ohne StreamBuilder
wir uns StreamBuilder
zu abonnieren und Widgets neu zu zeichnen
Google hat gute Beispiele für die Verwendung dieses Zustandsverwaltungsmusters, da es weit verbreitet ist und vom Unternehmen dringend empfohlen wird.
Ich selbst empfehle dringend, diesen Ansatz zur Verwaltung des lokalen Zustands zu verwenden, aber er eignet sich sogar zur Verwaltung des globalen Zustands. Im letzteren Fall tritt jedoch ein Problem auf - wo und wie BLoC korrekt implementiert wird, damit verschiedene Komponenten darauf zugreifen können, und dann betritt Redux die Szene.
Redux und BLoC - die perfekte Mischung für mich
Eines der Ziele, die ich am Anfang des Artikels beschrieben habe, war es, etwas zu finden, das weit verbreitet und vorhersehbar ist, und dies ist Redux - ein Muster und eine Reihe von Werkzeugen, die uns zusammen helfen, den globalen Zustand zu verwalten. Es hat drei Grundprinzipien im Kern:
Die einzige Quelle der Wahrheit ist, dass der gesamte Status des
state
Ihrer Anwendung in einem Baumobjekt in einem einzelnen
store
- Der Status ist schreibgeschützt. Die einzige Möglichkeit, den Status zu ändern, besteht darin, ein spezielles Aktionsobjekt aufzurufen, das beschreibt, was mit dem Status geschehen soll
- Änderungen werden mit reinen Funktionen vorgenommen - um festzustellen, welche Zustandsänderungen
reducer
, schreiben Sie die reine " reducer
-Funktion, die keine Nebenwirkungen verursachen sollte "Link zum Beispielcode"
Link zum Originalbeitrag, aus dem das Bild stammtDieser Ansatz zur Verwaltung des Status wird von Webentwicklern weitgehend akzeptiert, und sein Auftreten auf Mobilgeräten wird den Entwicklern von Web- und Mobilanwendungen zugute kommen.
Brian Egan entwickelt sowohl das Original
Redux als auch
flutter_redux und er hat auch eine großartige
Todo-Anwendung erstellt, in der er viele Architekturmuster angewendet hat, einschließlich Redux.
Angesichts aller Eigenschaften von Redux empfehle ich dringend, es zum Verwalten des globalen Status zu verwenden. Sie sollten jedoch sicher sein, dass Sie es nicht zum Verwalten des lokalen Status verwenden, wenn Sie Ihre Anwendung skalieren möchten.
Letzte Worte
In diesem Artikel gibt es keine vollständig korrekte oder falsche Lösung. Um zu entscheiden, welcher Ansatz in Ihrem Projekt angewendet werden soll, müssen Sie sich für Ihre Anforderungen entscheiden. Für mich und meine Ziele ermöglicht die Kombination von Redux und BLoC, dass meine Projekte schnell und sicher wachsen, und erleichtert Drittentwicklern dank zugänglicher und übersichtlicher Tools die Eingabe dieser Projekte. Allerdings hat nicht jeder die gleichen Bedürfnisse und im Laufe der Zeit können Sie sowohl Probleme "in aktuellen Tools" als auch noch bessere Lösungen finden. Es ist sehr wichtig, immer neugierig zu bleiben, zu studieren und zu überlegen, ob dieses oder jenes Tool zu Ihnen passt.