flutter - ¿Cómo lidiar con la creación de widgets no deseados?
(1)
El método de construcción está diseñado de tal manera que debería ser puro / sin efectos secundarios . Esto se debe a que muchos factores externos pueden desencadenar una nueva creación de widget, como:
- Ruta pop / push, para animaciones in / out
- Cambiar el tamaño de la pantalla, generalmente debido a la apariencia del teclado o al cambio de orientación
- El widget padre recreado su hijo
-
Un objeto InheritedWidget del widget depende del cambio (
Class.of(context)
)
Esto significa que el método de
build
no
debe activar una llamada http ni modificar ningún estado
.
¿Cómo se relaciona esto con la pregunta?
El problema al que se enfrenta es que su método de compilación tiene efectos secundarios / no es puro, lo que hace que la llamada de compilación extraña sea problemática.
En lugar de evitar la llamada a la compilación, debe hacer que su método de compilación sea puro, de modo que pueda llamarlo en cualquier momento sin impacto.
En el caso de su ejemplo, transformaría su widget en un
StatefulWidget
luego extraería esa llamada HTTP al
initState
de
initState
de 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
},
);
}
}
- 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 revoloteo 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
dart
const
:
@override
Widget build(BuildContext context) {
return const DecoratedBox(
decoration: BoxDecoration(),
child: Text("Hello World"),
);
}
Gracias a la palabra clave
const
, la instancia de
DecoratedBox
seguirá siendo la misma incluso si la compilación se llamara cientos de veces.
Pero puedes 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 los nuevos valores, el
subtree
no se reconstruirá incluso si StreamBuilder / Column lo hace.
Sucede porque gracias al cierre, la instancia de
MyWidget
no cambió.
Este patrón se usa mucho en animaciones.
Los usuarios típicos son
AnimatedBuilder
y todas las Transiciones * como
AlignTransition
.
También puede almacenar el
subtree
en un campo de su clase, aunque menos recomendado, ya que rompe la recarga en caliente.
Por varias razones, a veces se vuelve a llamar el método de
build
de mis widgets.
Sé que sucede porque un padre actualizado.
Pero esto provoca efectos no deseados.
Una situación típica en la que causa problemas es cuando se usa
FutureBuilder
esta manera:
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: httpCall(),
builder: (context, snapshot) {
// create some layout here
},
);
}
En este ejemplo, si se volviera a llamar al método de compilación , se activaría otra solicitud http. Lo cual es indeseado.
Teniendo en cuenta esto, ¿cómo lidiar con la construcción no deseada? ¿Hay alguna manera de prevenir la llamada de construcción?