[解決済み] Flutter 継承されたウィジェットを正しく使うには?
質問
InheritedWidgetの正しい使用方法は何ですか?これまでのところ、ウィジェットツリーの下にデータを伝搬させる機会を与えるということを理解しました。極端な話、RootWidgetとして置くと、すべてのルートでツリー内のすべてのウィジェットからアクセスできるようになります。
しかし、InheritedWidgetは不変であり、どのようにそれを更新することができますか?そして、より重要なことは、どのように私のステートフルウィジェットは、そのサブツリーを再構築するためにトリガされるのですか?
残念ながら、このドキュメントは非常に不明瞭で、多くの人と議論した後、誰もそれを使用する正しい方法を本当に知らないようです。
Brian Eganからの引用を追加します。
はい、私はこれをツリーの下にデータを伝播させる方法だと考えています。私が見つけたもの API ドキュメントから、混乱しています。
継承されたウィジェットは、この方法で参照された場合、継承されたウィジェット自体の状態が変更されたときに この方法で参照すると、継承されたウィジェット自体が状態を変更したときに、コンシューマが再構築されます。
最初にこれを読んだとき、私は思いました。
InheritedWidgetにデータを詰め込んで、後で変異させればいいんだ。 変異が起こると、私のInheritedWidgetを参照しているすべてのWidgetが再構築されます。 私のInheritedWidgetを参照するすべてのWidgetを再構築します。 私が見つけたもの。
InheritedWidgetのStateを変異させるためには、それを の状態を変更するためには、それをStatefulWidgetでラップする必要があります。 StatefulWidgetの状態を実際に変異させて、このデータをInheritedWidgetに渡す。 は、そのデータをすべての子ウィジェットに渡します。しかし、この場合 を参照するウィジェットだけでなく、StatefulWidgetの下のツリー全体が再構築されるようです。 InheritedWidgetを参照するウィジェットだけでなく、StatefulWidgetの下のツリー全体が再構築されるようです。これは正しいのでしょうか? それとも、更新時に を参照するウィジェットをスキップする方法を知っていますか?
どのように解決するのですか?
この問題は、あなたの引用文に起因しており、それは正しくありません。
あなたが言ったように、InheritedWidgetsは、他のウィジェットのように、不変である。したがって、それらは を更新します。 . それらは新しく作成されます。
そのことは
InheritedWidgetはデータを保持する以外には何もしないシンプルなウィジェットで
. 更新のロジックも何も持っていません。
しかし、他のウィジェットのように、これは
Element
.
そして何だと思いますか?これはミュータブルで、flutterは可能な限りこれを再利用します!
訂正後の引用文は:
に関連付けられたInheritedWidgetは、この方法で参照されると、コンシューマが再構築されることになります。 InheritedElement が変更されたときに再構築されます。
ウィジェット/エレメント/レンダーボックスがどのようにプラグインされているかについての素晴らしいトークがあります。 . しかし、簡単に言えば、それらは以下のようなものです(左が典型的なウィジェット、真ん中が「エレメント」、右が「レンダーボックス」) :
ということです。新しいウィジェットをインスタンス化するとき、flutter はそれを古いものと比較します。RenderBoxを指しているquot;Element"を再利用します。そして を変更します。 RenderBoxのプロパティを変更します。
なるほど、しかしこれが私の質問にどう答えるのでしょうか?
InheritedWidgetをインスタンス化した後
context.inheritedWidgetOfExactType
(または
MyClass.of
でも基本的に同じです); 暗黙の了解として、このメソッドは
Element
に関連付けられた
InheritedWidget
. そして、その
Element
が新しいウィジェットを取得するたびに、前のメソッドを呼び出したすべてのウィジェットを強制的に更新します。
要するに、既存の
InheritedWidget
を新しいものに置き換えると、flutter はそれが変更されたことを認識します。そして、バインドされたウィジェットに変更の可能性を通知します。
すべてを理解したのであれば、すでに解決策を推測しているはずです。
をラップして
InheritedWidget
の中に
StatefulWidget
を作成すると、新しい
InheritedWidget
を作成します。
実際のコードでの最終結果は、:
class MyInherited extends StatefulWidget {
static MyInheritedData of(BuildContext context) =>
context.inheritFromWidgetOfExactType(MyInheritedData) as MyInheritedData;
const MyInherited({Key key, this.child}) : super(key: key);
final Widget child;
@override
_MyInheritedState createState() => _MyInheritedState();
}
class _MyInheritedState extends State<MyInherited> {
String myField;
void onMyFieldChange(String newValue) {
setState(() {
myField = newValue;
});
}
@override
Widget build(BuildContext context) {
return MyInheritedData(
myField: myField,
onMyFieldChange: onMyFieldChange,
child: widget.child,
);
}
}
class MyInheritedData extends InheritedWidget {
final String myField;
final ValueChanged<String> onMyFieldChange;
MyInheritedData({
Key key,
this.myField,
this.onMyFieldChange,
Widget child,
}) : super(key: key, child: child);
static MyInheritedData of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<MyInheritedData>();
}
@override
bool updateShouldNotify(MyInheritedData oldWidget) {
return oldWidget.myField != myField ||
oldWidget.onMyFieldChange != onMyFieldChange;
}
}
しかし、新しい InheritedWidget を作成すると、ツリー全体が再構築されるのではないでしょうか?
いいえ、必ずしもそうなるわけではありません。新しい InheritedWidget は、以前とまったく同じ子を持つ可能性があるからです。正確には、同じインスタンスを意味します。 以前と同じインスタンスを持つウィジェットは、再構築されません。
そして最も多い状況(アプリのルートにinheritedWidgetを持つ)では、継承されたウィジェットは 一定 . そのため、不要な再構築はありません。
関連
-
[解決済み] Dartは参照渡しになりますか?[重複あり]
-
[解決済み] Flutterでウィジェットにボーダーを追加するには?
-
[解決済み】メッセージ「flutter run: 接続されたデバイスがありません"
-
[解決済み】画面の幅や高さに対する割合で要素をサイズ調整する方法
-
[解決済み】縦型ビューポートの高さが制限されない。
-
[解決済み】Flutterで少し遅れてからコードを実行する方法は?
-
[解決済み] ポップアップ時にFlutterナビゲータの状態を再読み込みするように強制する
-
[解決済み] フラッター : 垂直中心柱
-
[解決済み] FlutterError: アセットをロードできない
-
[解決済み] dispose() の後に setState() が呼ばれる。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
flutter,コマンド PhaseScriptExecution が 0 以外の終了コードで失敗しました。
-
[解決済み] Flutterでgoogleとyoutubeの両方にログインする
-
[解決済み] FlutterでButtonを無効にするには?
-
WindowsでFlutterを設定する際にAndroidのライセンス状態がわからない
-
[解決済み】Flutterでアプリケーションランチャーのアイコンを変更するには?
-
[解決済み】FlutterでToastを作成する方法
-
[解決済み] フラッター エキスパンドとフレキシブル
-
[解決済み] InkWellでリップルエフェクトが表示されない
-
[解決済み] フラッター : 垂直中心柱
-
[解決済み] Flutterで「戻る」ボタンを上書きするには?[重複している]。