TL; DR
updateShouldNotifyメソッド内で重い計算を使用せず、ウィジェットの作成時にnewではなく constを使用する
まず、ウィジェット、要素、レンダリングオブジェクトとは何かを理解する必要があります。
- レンダーオブジェクトは、画面に実際にレンダリングされるものです。それらは変更可能で、ペインティングとレイアウトロジックが含まれています。レンダーツリーは、Webのドキュメントオブジェクトモデル(DOM)とよく似ており、レンダーオブジェクトをこのツリーのDOMノードとして見ることができます。
- ウィジェット -何をレンダリングするかを記述したものです。それらは不変で安価です。したがって、ウィジェットが「何ですか?」(宣言型アプローチ)の質問に答えると、Renderオブジェクトは「どのように?」(命令型アプローチ)の質問に答えます。Webからの類推は「仮想DOM」です。
- Element / BuildContext- ウィジェットとレンダーオブジェクト間のプロキシです。ツリー内のウィジェットの位置に関する情報と、対応するウィジェットが変更されたときにRenderオブジェクトを更新する方法が含まれています。
これで、InheritedWidgetとBuildContextのメソッドinheritFromWidgetOfExactTypeに飛び込む準備ができました。
例として、InheritedWidgetに関するFlutterのドキュメントの次の例を検討することをお勧めします。
class FrogColor extends InheritedWidget {
const FrogColor({
Key key,
@required this.color,
@required Widget child,
}) : assert(color != null),
assert(child != null),
super(key: key, child: child);
final Color color;
static FrogColor of(BuildContext context) {
return context.inheritFromWidgetOfExactType(FrogColor);
}
@override
bool updateShouldNotify(FrogColor old) {
return color != old.color;
}
}
InheritedWidget-この場合、1つの重要なメソッド-updateShouldNotifyを実装する単なるウィジェット。
updateShouldNotify -1つのパラメーターoldWidgetを受け入れ、ブール値(trueまたはfalse)を返す関数。
他のウィジェットと同様に、InheritedWidgetには対応するElementオブジェクトがあります。それはあるInheritedElement。InheritedElementは、新しいウィジェットを作成するたびに、ウィジェットでupdateShouldNotifyを呼び出します(祖先でsetStateを呼び出します)。ときupdateShouldNotifyは返す真 InheritedElementを反復依存関係(?)と呼び出し方法のdidChangeDependenciesその上を。
InheritedElementはどこで依存関係を取得しますか?ここでは、inheritFromWidgetOfExactTypeメソッドを確認する必要があります。
inheritFromWidgetOfExactType-このメソッドはBuildContextで定義され、
すべての ElementがBuildContextインターフェースを実装します(Element == BuildContext)。したがって、すべての要素にこのメソッドがあります。
inheritFromWidgetOfExactTypeのコードを見てみましょう:
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[targetType];
if (ancestor != null) {
assert(ancestor is InheritedElement);
return inheritFromElement(ancestor, aspect: aspect);
}
ここでは、タイプによってマップされた_inheritedWidgetsで祖先を見つけようとします。祖先が見つかった場合は、inheritFromElementを呼び出します。
inheritFromElementのコード:
InheritedWidget inheritFromElement(InheritedElement ancestor, { Object aspect }) {
assert(ancestor != null);
_dependencies ??= HashSet<InheritedElement>();
_dependencies.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget;
}
- 現在の要素の依存関係として祖先を追加します(_dependencies.add(ancestor))
- 現在の要素を祖先の依存関係に追加します(ancestor.updateDependencies(this、aspect))
- inheritFromWidgetOfExactTypeの結果として祖先のウィジェットを返します(ancestor.widgetを返します)
これで、InheritedElementが依存関係を取得する場所がわかりました。
次に、didChangeDependenciesメソッドを見てみましょう。すべての要素にこのメソッドがあります:
void didChangeDependencies() {
assert(_active); // otherwise markNeedsBuild is a no-op
assert(_debugCheckOwnerBuildTargetExists('didChangeDependencies'));
markNeedsBuild();
}
ご覧のとおり、このメソッドは要素をダーティとしてマークし、この要素は次のフレームで再構築する必要があります。再構築とは、対応するウィジェット要素でビルドメソッドを呼び出すことを意味します。
しかし、「InheritedWidgetを再構築すると、サブツリー全体が再構築される」とはどうでしょうか。ここで、ウィジェットは不変であり、新しいウィジェットを作成するとFlutterがサブツリーを再構築することを覚えておく必要があります。どうすれば修正できますか?
- 手でウィジェットをキャッシュする(手動)
- constは値/クラスのインスタンスを1つだけ作成するため、const を使用します