Pour diverses raisons, la méthode build
de mes widgets est parfois appelée à nouveau.
Je sais que cela se produit parce qu'un parent a mis à jour. Mais cela provoque des effets indésirables. Une situation typique où cela pose des problèmes est la suivante: FutureBuilder
:
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: httpCall(),
builder: (context, snapshot) {
// create some layout here
},
);
}
Dans cet exemple, si la méthode build devait être appelée à nouveau, elle déclencherait une autre requête http. Ce qui est indésirable.
Compte tenu de cela, comment faire face à la construction non désirée? Y a-t-il un moyen d'empêcher l'appel à la construction?
La méthode build est conçue de telle sorte qu'elle soit pure/sans effets secondaires . En effet, de nombreux facteurs externes peuvent déclencher une nouvelle construction de widget, tels que:
Class.of(context)
) changeCela signifie que la méthode build
devrait ne pas déclencher un appel http ou modifier un état quelconque.
Comment est-ce lié à la question?
Le problème que vous rencontrez est que votre méthode de génération a des effets secondaires/n'est pas pure, ce qui rend difficile un appel de génération superflue.
Au lieu d'empêcher l'appel de génération, vous devez rendre votre méthode de génération 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 extrayez 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
},
);
}
}
Lorsque l'instance d'un widget reste la même; Flutter délibérément ne reconstruira pas les enfants. Cela signifie 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 les constructeurs Dart const
:
@override
Widget build(BuildContext context) {
return const DecoratedBox(
decoration: BoxDecoration(),
child: Text("Hello World"),
);
}
Grâce à ce mot-clé const
, l'instance de DecoratedBox
restera la même, même si la construction a été appelée 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 informé de nouvelles valeurs, subtree
ne sera pas reconstruit, même si StreamBuilder/Column le fait. Cela se produit parce que, grâce à la fermeture, l'instance de MyWidget
n'a pas changé.
Ce modèle est beaucoup utilisé dans les animations. Les utilisateurs typiques sont AnimatedBuilder
et toutes les * Transition telles que AlignTransition
.
Vous pouvez également stocker subtree
dans un champ de votre classe, bien que cela soit moins recommandé car il empêche le rechargement à chaud.