Eine leicht verständliche reaktive Staatsmanagementlösung für Flutter.
Der Staat wird in einem oder mehreren Value oder ähnlichen Klassen gehalten, in denen ValueNotifier implementiert wird. Dies sind Standard -Flutter -Schnittstellen, die jeder aus TextEditingController , Animation usw. kennt.
Darüber hinaus können Sie ListValue und MapValue verwenden, um beobachtbare List und Map zu erstellen, die Sie über feinkörnige Änderungsereignisse informieren können (anstelle des gesamten Wertes ändert sich).
AutoBuild baut Ihre Widgets automatisch um, wenn ein ValueNotifier (oder eine Listenable ) Benachrichtigung eine Benachrichtigung auslöst. Es ähnelt dem ValueListenableBuilder von Flutter, aber es kann mehrere Abhängigkeiten verfolgen und funktioniert auch mit Listenable .
Es ist nicht erforderlich, addListener / removeListener aufzurufen. get() den Wert direkt, während AutoBuild sich um die Verfolgung Ihrer Abhängigkeiten kümmert.
Im Gegensatz zu InheritedWidget und Provider erhalten Sie eine feinkörnige Kontrolle darüber, was wieder aufgebaut wird.
Standard -Flutterklassen wie TextEditingController und Animation implementieren ValueListenable und arbeiten so gut mit AutoBuild zusammen.
DerivedValue ist ein beobachtbarer Wert, der von anderen beobachtbaren Werten berechnet (abgeleitet) wird.
Außerdem bieten ListValue und MapValue .map() und andere Vorgänge zum Erstellen abgeleiteter Container bereit, die sich per Elektromotion auf dem Laufenden halten.
Der resultierende Code ist viel einfacher als dieselbe Lösung in Block oder Redux.
StreamBuilder , kein asynchrones Laden von Widgets (es sei denn, Sie brauchen es wirklich).switch() Anweisungen. HINWEIS: Weitere Informationen finden Sie in Referenz.
Ein einfaches Beispiel AutoBuild :
import 'package:flutter/material.dart' ;
import 'package:reactive_state/reactive_state.dart' ;
class MyPage extends StatelessWidget {
MyPage ({ Key key, @required this .counter}) : super (key : key);
final ValueNotifier < int > counter;
@override
Widget build ( BuildContext context) {
return Scaffold (
appBar : AppBar (title : Text ( 'Counter' )),
body : Column (
children : < Widget > [
AutoBuild (builder : (context, get , track) {
return Text ( 'Counter: ${ get ( counter )}' );
}),
MaterialButton (
onPressed : () => counter.value ++ ,
child : Text ( 'Increment' ),
),
],
),
);
}
}Beachten Sie, dass Sie in realen Anwendungen den Zustand nicht direkt mutieren sollten, sondern dies in separate Methoden einfügen sollten, z. B. in einem über das Anbieterpaket zugänglichen Objekt.
Schauen Sie sich auch das Beispiel im Repo an.
Außerhalb von Widgets möchten Sie möglicherweise noch auf Zustandsänderungen reagieren. Sie können dies mit autoRun() und AutoRunner tun (siehe Referenz für Einzelheiten).
Als Alternative zu ValueNotifier können Sie auch Value von reactive_state verwenden, die eine update() -Methode zum Ändern komplexerer Objekte bietet:
class User {
String name = '' ;
String email = '' ;
// ...
}
var userValue = Value ( User ());
userValue. update ((user) {
user.name = 'Adam' ;
user.email = '[email protected]' ;
}); Dies ähnelt dem Calling setState() mit StatefulWidget . Mit update() können Sie mehrere Attribute ändern und Value wird nach Abschluss einer einzelnen Benachrichtigung ausgelöst - auch wenn nichts geändert wurde (daher müssen Sie Vergleichsbetreiber für komplexe Objekte nicht implementieren).
DerivedValue ist ein dynamisch berechnetes ValueListenable das seinen Wert aktualisiert, wenn sich seine Abhängigkeiten ändern:
var user = Value ( User ());
var emailLink = DerivedValue (( get , track) => 'mailto:${ get ( user ). email }' ); Hier kann emailLink selbst beobachtet werden und wird aktualisiert, wenn user geändert wird.
Ein einfaches Beispiel, das ein paar Dinge zeigt, die getan werden können:
final listValue = ListValue ( < int > []);
final mappedList = listValue. map ((x) => x. toString ());
final listToMap = mappedList. toMap ((x) => MapEntry ( 2 * int . parse (x), x));
final invertedMap = listToMap. map ((k, v) => MapEntry (v, k));
listValue. addAll ([ 4 , 1 ]);
// => invertedMap.value == {'4': 8, '1': 2}