Il metodo di costruzione è progettato in modo tale che dovrebbe essere puro / senza effetti collaterali . Questo perché molti fattori esterni possono innescare una nuova build di widget, come:
- Percorso pop / push
- Ridimensionamento dello schermo, in genere dovuto all'aspetto della tastiera o al cambio di orientamento
- Il widget padre ha ricreato il figlio
- In EreditatoWidget il widget dipende dalla
Class.of(context)
modifica ( modello)
Ciò significa che il build
metodo non deve attivare una chiamata http o modificare alcuno stato .
In che modo ciò è legato alla domanda?
Il problema che stai affrontando è che il tuo metodo di build ha effetti collaterali / non è puro, il che rende problematica la chiamata di build estranea.
Invece di impedire la chiamata build, dovresti rendere puro il tuo metodo build, in modo che possa essere chiamato in qualsiasi momento senza impatto.
Nel caso del tuo esempio, trasformeresti il tuo widget in un StatefulWidget
estratto quindi quella chiamata HTTP al initState
tuo 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
},
);
}
}
Lo so già. Sono venuto qui perché voglio davvero ottimizzare le ricostruzioni
È anche possibile creare un widget in grado di ricostruire senza forzare anche i suoi figli a costruire.
Quando l'istanza di un widget rimane la stessa; Flutter non ricostruirà intenzionalmente i bambini. Implica che è possibile memorizzare nella cache parti dell'albero del widget per impedire ricostruzioni non necessarie.
Il modo più semplice è usare i const
costruttori di freccette :
@override
Widget build(BuildContext context) {
return const DecoratedBox(
decoration: BoxDecoration(),
child: Text("Hello World"),
);
}
Grazie a quella const
parola chiave, l'istanza di DecoratedBox
rimane invariata anche se build è stata chiamata centinaia di volte.
Ma puoi ottenere lo stesso risultato manualmente:
@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 questo esempio, quando StreamBuilder riceve una notifica di nuovi valori, subtree
non verrà ricostruito anche se StreamBuilder / Column lo fa. Succede perché, grazie alla chiusura, l'istanza diMyWidget
non è cambiata.
Questo modello è molto usato nelle animazioni. Usi tipici sono AnimatedBuilder
e tutte le transizioni come AlignTransition
.
Potresti anche archiviare subtree
in un campo della tua classe, anche se meno raccomandato in quanto interrompe la funzione di ricarica rapida.