Die Erstellungsmethode ist so konzipiert, dass sie rein / ohne Nebenwirkungen sein sollte . Dies liegt daran, dass viele externe Faktoren einen neuen Widget-Build auslösen können, z.
- Route Pop / Push
- Größenänderung des Bildschirms, normalerweise aufgrund des Erscheinungsbilds der Tastatur oder der Änderung der Ausrichtung
- Das übergeordnete Widget hat sein untergeordnetes Element neu erstellt
- Ein InheritedWidget, von dem das Widget abhängt (
Class.of(context)
Muster-) Änderung
Dies bedeutet, dass die build
Methode keinen http-Aufruf auslösen oder einen Status ändern sollte .
Wie hängt das mit der Frage zusammen?
Das Problem, mit dem Sie konfrontiert sind, besteht darin, dass Ihre Erstellungsmethode Nebenwirkungen hat / nicht rein ist, was einen fremden Erstellungsaufruf problematisch macht.
Anstatt einen Build-Aufruf zu verhindern, sollten Sie Ihre Build-Methode rein machen, damit sie jederzeit ohne Auswirkungen aufgerufen werden kann.
Im Fall von Ihrem Beispiel, würden Sie das Widget in eine Transformation StatefulWidget
dann die , dass die HTTP - Aufruf extrahiert initState
Ihre State
:
class Example extends StatefulWidget {
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
Future<int> future;
@override
void initState() {
future = Future.value(42);
super.initState();
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: future,
builder: (context, snapshot) {
// create some layout here
},
);
}
}
Ich weiß das schon. Ich bin hierher gekommen, weil ich Umbauten wirklich optimieren möchte
Es ist auch möglich, ein Widget neu zu erstellen, ohne dass seine Kinder ebenfalls zum Erstellen gezwungen werden.
Wenn die Instanz eines Widgets gleich bleibt; Flattern baut Kinder absichtlich nicht wieder auf. Dies bedeutet, dass Sie Teile Ihres Widget-Baums zwischenspeichern können, um unnötige Neuerstellungen zu vermeiden.
Der einfachste Weg ist die Verwendung von Dartkonstruktoren const
:
@override
Widget build(BuildContext context) {
return const DecoratedBox(
decoration: BoxDecoration(),
child: Text("Hello World"),
);
}
Dank dieses const
Schlüsselworts DecoratedBox
bleibt die Instanz von gleich, auch wenn der Build hunderte Male aufgerufen wurde.
Sie können jedoch das gleiche Ergebnis manuell erzielen:
@override
Widget build(BuildContext context) {
final subtree = MyWidget(
child: Text("Hello World")
);
return StreamBuilder<String>(
stream: stream,
initialData: "Foo",
builder: (context, snapshot) {
return Column(
children: <Widget>[
Text(snapshot.data),
subtree,
],
);
},
);
}
In diesem Beispiel wird StreamBuilder, wenn er über neue Werte benachrichtigt subtree
wird, auch dann nicht neu erstellt, wenn StreamBuilder / Column dies tut. Es passiert, weil sich dank der Schließung die Instanz von MyWidget
nicht geändert hat.
Dieses Muster wird häufig in Animationen verwendet. Typische Verwendungen sind AnimatedBuilder
und alle Übergänge wie AlignTransition
.
Sie können auch subtree
in einem Feld Ihrer Klasse speichern , obwohl dies weniger empfohlen wird, da dadurch die Hot-Reload-Funktion unterbrochen wird.