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 buildmetodo 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 StatefulWidgetestratto quindi quella chiamata HTTP al initStatetuo 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 constcostruttori di freccette :
@override
Widget build(BuildContext context) {
return const DecoratedBox(
decoration: BoxDecoration(),
child: Text("Hello World"),
);
}
Grazie a quella constparola chiave, l'istanza di DecoratedBoxrimane 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, subtreenon 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 AnimatedBuildere tutte le transizioni come AlignTransition.
Potresti anche archiviare subtreein un campo della tua classe, anche se meno raccomandato in quanto interrompe la funzione di ricarica rapida.