Aus öffentlichen Paketdaten erstellte Orientierung.
Scoped Model ist eine leichte Zustandsverwaltungslösung für Flutter, die die reaktive Modellfreigabe über einen Widgetbaum ermöglicht. Es bietet eine einfache Möglichkeit, ein Modellobjekt durch die Widget-Hierarchie nach unten zu übergeben, sodass untergeordnete Widgets das Modell reaktiv zugreifen und aktualisieren können. Das Paket verwendet einen scoped-Ansatz, der sicherstellt, dass nur relevante Widgets neu erstellt werden, wenn sich das Modell ändert, was die Leistung verbessert. Es ist ideal für kleine bis mittelgroße Apps, bei denen eine vollwertige Zustandsverwaltungslösung wie Provider oder Bloc überkill wäre. Mit Unterstützung für alle wichtigen Plattformen lässt es sich nahtlos in bestehende Flutter-Projekte integrieren.
Anwendungsfälle
Einfache Zustandsverwaltung in kleinen Anwendungen
Daten über mehrere Widgets teilen
Reaktive UI-Updates basierend auf Modelländerungen
Formularzustände verwalten
Implementierung von Thema oder Benutzereinstellungen
Hauptmerkmale
reaktive Modellweitergabe
Minimales Boilerplate
Plattformübergreifende Unterstützung
Einfache Integration in bestehenden Code
Automatisches Neuerstellen des Widgets bei Modelländerung
Geeignet für
Anfänger-Flutter-Entwickler
Leichte Zustandsanforderungen
Prototyping
Apps mit moderater Zustandskomplexität
Projekte, die schwere State-Management-Frameworks vermeiden
Hinweise
Nicht ideal für großskalige Anwendungen
Begrenzte integrierte Debugging-Tools
Weniger flexibel als fortgeschrittene Lösungen wie Riverpod
Manuelle Behandlung komplexer Zustandsübergänge
Keine eingebaute Fehlerbehandlung für Modellaktualisierungen
Original-README
Originaler README-Schnappschuss aus dem verknüpften Quell-Repository. Aktuelle Inhalte finden Sie im Repository.
scoped_model
A set of utilities that allow you to easily pass a data Model from a parent Widget down to its descendants. In addition, it also rebuilds all of the children that use the model when the model is updated. This library was originally extracted from the Fuchsia codebase.
This Library provides three main classes:
The Model class. You will extend this class to create your own Models, such as SearchModel or UserModel. You can listen to Models for changes!
The ScopedModel Widget. If you need to pass a Model deep down your Widget hierarchy, you can wrap your Model in a ScopedModel Widget. This will make the Model available to all descendant Widgets.
The ScopedModelDescendant Widget. Use this Widget to find the appropriate ScopedModel in the Widget tree. It will automatically rebuild whenever the Model notifies that change has taken place.
This library is built upon several features of Flutter:
The Model class implements the Listenable interface
AnimationController and TextEditingController are also Listenables
The Model is passed down the Widget tree using an InheritedWidget. When an InheritedWidget is rebuilt, it will surgically rebuild all of the Widgets that depend on its data. No need to manage subscriptions!
It uses the AnimatedBuilder Widget under the hood to listen to the Model and rebuild the InheritedWidget when the model changes.
Examples
Counter App - Introduction to the tools provided by Scoped Model.
Todo App - Shows how to write a Todo app with persistence and tests.
Usage
Let's demo the basic usage with the all-time favorite: A counter example!
// Start by creating a class that holds some view the app's state. In// our example, we'll have a simple counter that starts at 0 can be // incremented.//// Note: It must extend from Model. classCounterModelextendsModel{
int _counter = 0;
intget counter => _counter;
voidincrement() {
// First, increment the counter
_counter++;
// Then notify all the listeners.notifyListeners();
}
}
// Create our App, which will provide the `CounterModel` to // all children that require it! classCounterAppextendsStatelessWidget{
@overrideWidgetbuild(BuildContext context) {
// First, create a `ScopedModel` widget. This will provide // the `model` to the children that request it. returnnewScopedModel<CounterModel>(
model: newCounterModel(),
child: newColumn(children: [
// Create a ScopedModelDescendant. This widget will get the// CounterModel from the nearest ScopedModel<CounterModel>. // It will hand that model to our builder method, and rebuild // any time the CounterModel changes (i.e. after we // `notifyListeners` in the Model). newScopedModelDescendant<CounterModel>(
builder: (context, child, model) => newText('${model.counter}'),
),
newText("Another widget that doesn't depend on the CounterModel")
])
);
}
}
Finding the Model
There are two ways to find the Model provided by the ScopedModel Widget.
Use the ScopedModelDescendant Widget. It will find the Model and run the
builder function whenever the Model notifies the listeners.
Use the ScopedModel.of static method directly. To make this method more readable for frequent access, you can consider adding your own of method to your own Model classes like so:
classCounterModelextendsModel{
// .../// Wraps [ScopedModel.of] for this [Model].staticCounterModelof(BuildContext context) =>
ScopedModel.of<CounterModel>(context);
}
Listening to multiple Models in a build function
In many cases, it makes sense to split your Models apart into logical components
by functionality. For example, rather than having an AppModel that contains
all of your application logic, it can often make more sense to split models
apart into a UserModel, a SearchModel and a ProductModel, for example.
However, if you need to display information from two of these models in a single
Widget, you might be wondering how to achieve that! To do so, you have two
options:
Use multiple ScopedModelDescendant Widgets
Use multiple ScopedModel.of calls. No need to manage subscriptions,
Flutter takes care of all of that through the magic of InheritedWidgets.
classCombinedWidgetextendsStatelessWidget{
@overrideWidgetbuild(BuildContext context) {
final username =
ScopedModel.of<UserModel>(context, rebuildOnChange: true).username;
final counter =
ScopedModel.of<CounterModel>(context, rebuildOnChange: true).counter;
returnText('$username tapped the button $counter times');
}
}