El método de construcción está diseñado de tal manera que debe ser puro / sin efectos secundarios . Esto se debe a que muchos factores externos pueden desencadenar una nueva compilación de widgets, como:
- Ruta pop / push
- Cambiar el tamaño de la pantalla, generalmente debido a la apariencia del teclado o al cambio de orientación
- El widget principal recreó a su hijo
- Un widget heredado el widget depende del
Class.of(context)
cambio ( patrón)
Esto significa que el build
método no debe activar una llamada http ni modificar ningún estado .
¿Cómo se relaciona esto con la pregunta?
El problema que enfrenta es que su método de compilación tiene efectos secundarios / no es puro, lo que hace que las llamadas de compilación extrañas sean problemáticas.
En lugar de evitar la llamada de compilación, debe hacer que su método de compilación sea puro, para que pueda llamarse en cualquier momento sin impacto.
En el caso de su ejemplo, transformaría su widget en un StatefulWidget
extracto y luego extraería esa llamada HTTP a initState
su 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
},
);
}
}
Ya se esto. Vine aquí porque realmente quiero optimizar las reconstrucciones
También es posible hacer un widget capaz de reconstruir sin obligar a sus hijos a construir también.
Cuando la instancia de un widget permanece igual; El aleteo a propósito no reconstruirá a los niños. Implica que puede almacenar en caché partes de su árbol de widgets para evitar reconstrucciones innecesarias.
La forma más fácil es usar const
constructores de dardos :
@override
Widget build(BuildContext context) {
return const DecoratedBox(
decoration: BoxDecoration(),
child: Text("Hello World"),
);
}
Gracias a esa const
palabra clave, la instancia de DecoratedBox
permanecerá igual incluso si se llamara build cientos de veces.
Pero puede lograr el mismo resultado 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,
],
);
},
);
}
En este ejemplo, cuando se notifica a StreamBuilder sobre nuevos valores, subtree
no se reconstruirá incluso si lo hace StreamBuilder / Column. Ocurre porque, gracias al cierre, la instancia de MyWidget
no cambió.
Este patrón se usa mucho en animaciones. Los usos típicos son AnimatedBuilder
y todas las transiciones como AlignTransition
.
También puede almacenar subtree
en un campo de su clase, aunque es menos recomendable ya que rompe la función de recarga en caliente.