さまざまな理由により、build
ウィジェットのメソッドが再度呼び出されることがあります。
親がアップデートされたためにこれが発生することはわかっています。しかし、これは望ましくない影響を引き起こします。問題が発生する典型的な状況は、FutureBuilder
次の方法を使用する場合です。
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: httpCall(),
builder: (context, snapshot) {
// create some layout here
},
);
}
この例では、ビルドメソッドが再度呼び出されると、別の HTTP 要求がトリガーされます。これは望ましくありません。
これを考慮すると、不要なビルドにはどのように対処すればよいでしょうか? ビルド呼び出しを防ぐ方法はありますか?
ベストアンサー1
ビルドメソッドは、純粋で副作用のないように設計されています。これは、次のような多くの外部要因によって新しいウィジェットのビルドがトリガーされる可能性があるためです。
- ルートポップ/プッシュ
- 画面のサイズ変更(通常はキーボードの外観や向きの変更による)
- 親ウィジェットが子ウィジェットを再作成した
- ウィジェットが依存するInheritedWidget(
Class.of(context)
パターン)の変更
つまり、build
メソッドはhttp 呼び出しをトリガーしたり、状態を変更したりしてはならないということです。
これは質問とどう関係するのでしょうか?
あなたが直面している問題は、ビルド方法に副作用があり、純粋ではないため、余分なビルド呼び出しが面倒になることです。
ビルド呼び出しを防止する代わりに、ビルド メソッドを純粋にして、影響を与えることなくいつでも呼び出せるようにする必要があります。
あなたの例の場合、ウィジェットを に変換し、StatefulWidget
その HTTP 呼び出しを の に抽出しinitState
ますState
。
class Example extends StatefulWidget {
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
Future<int> future;
@override
void initState() {
super.initState();
future = Future.value(42);
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: future,
builder: (context, snapshot) {
// create some layout here
},
);
}
}
これはもうわかっています。再構築を最適化したいのでここに来ました
子ウィジェットのビルドを強制せずにウィジェットを再構築できるようにすることも可能です。
ウィジェットのインスタンスが同じままの場合、Flutter は意図的に子を再構築しません。これは、ウィジェット ツリーの一部をキャッシュして、不要な再構築を防ぐことができることを意味します。
最も簡単な方法は、Dartconst
コンストラクターを使用することです。
@override
Widget build(BuildContext context) {
return const DecoratedBox(
decoration: BoxDecoration(),
child: Text("Hello World"),
);
}
このキーワードのおかげで、ビルドが何百回呼び出されても のconst
インスタンスは同じままになります。DecoratedBox
ただし、手動でも同じ結果を得ることができます。
@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,
],
);
},
);
}
この例では、StreamBuilder に新しい値が通知されると、 StreamBuilder/Column が再構築されても、は再構築されません。これは、クロージャのおかげで、のインスタンスが変更されなかったsubtree
ために発生します。MyWidget
このパターンはアニメーションでよく使用されます。典型的な使用法はAnimatedBuilder
、 や などのすべてのトランジションですAlignTransition
。
クラスのフィールドに保存することもできますsubtree
が、ホットリロード機能が壊れるためあまりお勧めできません。