La méthode de construction est conçue de manière à être pure / sans effets secondaires . En effet, de nombreux facteurs externes peuvent déclencher une nouvelle construction de widget, tels que:
- Route pop / push
- Redimensionnement de l'écran, généralement en raison de l'apparence du clavier ou du changement d'orientation
- Le widget parent a recréé son enfant
- Un InheritedWidget dont le widget dépend du
Class.of(context)
changement (de modèle)
Cela signifie que la build
méthode ne doit pas déclencher un appel http ni modifier aucun état .
Comment cela est-il lié à la question?
Le problème auquel vous êtes confronté est que votre méthode de build a des effets secondaires / n'est pas pure, ce qui rend les appels de build superflus gênants.
Au lieu d'empêcher l'appel de build, vous devez rendre votre méthode de build pure, afin qu'elle puisse être appelée à tout moment sans impact.
Dans le cas de votre exemple, vous transformeriez votre widget en un StatefulWidget
puis extrairiez cet appel HTTP vers le initState
de votre 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
},
);
}
}
Je le sais déjà. Je suis venu ici parce que je veux vraiment optimiser les reconstructions
Il est également possible de créer un widget capable de se reconstruire sans forcer ses enfants à construire aussi.
Lorsque l'instance d'un widget reste la même; Flutter ne reconstruira pas volontairement les enfants. Cela implique que vous pouvez mettre en cache des parties de votre arborescence de widgets pour éviter les reconstructions inutiles.
Le moyen le plus simple consiste à utiliser des const
constructeurs de fléchettes :
@override
Widget build(BuildContext context) {
return const DecoratedBox(
decoration: BoxDecoration(),
child: Text("Hello World"),
);
}
Grâce à ce const
mot - clé, l'instance de DecoratedBox
restera la même même si build a été appelé des centaines de fois.
Mais vous pouvez obtenir le même résultat manuellement:
@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,
],
);
},
);
}
Dans cet exemple, lorsque StreamBuilder est notifié des nouvelles valeurs, subtree
il ne sera pas reconstruit même si StreamBuilder / Column le fait. Cela arrive parce que, grâce à la fermeture, l'instance de MyWidget
n'a pas changé.
Ce modèle est beaucoup utilisé dans les animations. Les utilisations typiques sont AnimatedBuilder
et toutes les transitions telles que AlignTransition
.
Vous pouvez également stocker subtree
dans un champ de votre classe, bien que moins recommandé car cela interrompt la fonction de rechargement à chaud.