O método de compilação foi projetado de forma a ser puro / sem efeitos colaterais . Isso ocorre porque muitos fatores externos podem acionar uma nova compilação de widget, como:
- Rota pop / push
- Redimensionamento da tela, geralmente devido à aparência do teclado ou alteração de orientação
- O widget pai recriou seu filho
- Um InheritedWidget do widget depende da
Class.of(context)
alteração ( padrão)
Isso significa que o build
método não deve acionar uma chamada http ou modificar qualquer estado .
Como isso está relacionado à questão?
O problema que você está enfrentando é que seu método de compilação tem efeitos colaterais / não é puro, tornando a chamada de compilação estranha problemática.
Em vez de impedir a chamada de construção, você deve tornar seu método de construção puro, para que possa ser chamado a qualquer momento sem impacto.
No caso do seu exemplo, você transformaria seu widget em uma StatefulWidget
extração da chamada HTTP para a initState
sua 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
},
);
}
}
Eu já sei disso. Eu vim aqui porque eu realmente quero otimizar reconstruções
Também é possível criar um widget capaz de reconstruir sem forçar seus filhos a construir também.
Quando a instância de um widget permanece a mesma; A vibração propositalmente não reconstrói as crianças. Isso implica que você pode armazenar em cache partes da sua árvore de widgets para evitar reconstruções desnecessárias.
A maneira mais fácil é usar const
construtores de dardo :
@override
Widget build(BuildContext context) {
return const DecoratedBox(
decoration: BoxDecoration(),
child: Text("Hello World"),
);
}
Graças a essa const
palavra-chave, a instância de DecoratedBox
permanecerá a mesma, mesmo que a compilação tenha sido chamada centenas de vezes.
Mas você pode obter o mesmo 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,
],
);
},
);
}
Neste exemplo, quando o StreamBuilder for notificado sobre novos valores, subtree
não será reconstruído, mesmo que o StreamBuilder / Column o faça. Isso acontece porque, graças ao fechamento, a instância de MyWidget
não mudou.
Esse padrão é muito usado em animações. Os usos típicos são AnimatedBuilder
e todas as transições, como AlignTransition
.
Você também pode armazenar subtree
em um campo da sua classe, embora seja menos recomendado, pois quebra o recurso de recarga a quente.