Flutterウィジェットツリーのルーツは非常に深くなる可能性があります...
非常に深くなります。
Flutterウィジェットのコンポーネントの性質により、非常にエレガントでモジュール式の柔軟なアプリケーション設計が可能になります。ただし、これにより、コンテキストを渡すための多くの定型コードが生成される可能性もあります。accountIdとscopeIdをページから2レベル下のウィジェットに渡したいときに何が起こるかを確認してください。
class MyPage extends StatelessWidget {
final int accountId;
final int scopeId;
MyPage(this.accountId, this.scopeId);
Widget build(BuildContext context) {
return new MyWidget(accountId, scopeId);
}
}
class MyWidget extends StatelessWidget {
final int accountId;
final int scopeId;
MyWidget(this.accountId, this.scopeId);
Widget build(BuildContext context) {
// -
new MyOtherWidget(accountId, scopeId);
...
}
}
class MyOtherWidget extends StatelessWidget {
final int accountId;
final int scopeId;
MyOtherWidget(this.accountId, this.scopeId);
Widget build(BuildContext context) {
//
...
チェックを外したままにすると、このパターンはコードベース全体に非常に簡単に忍び寄る可能性があります。この方法で、30を超えるウィジェットを個人的にパラメーター化しました。
MyWidget
上記の例のように、作業時間のほぼ半分で、ウィジェットはパラメーターを受け取り、それらをさらに渡すだけでした。
MyWidgetの状態はパラメーターに依存しませんが、パラメーターが変更されるたびに再構築されます。
もちろん、...より良い方法がなければならない
の紹介InheritedWidgetを。
一言で言えば、これはサブツリーのルートでコンテキストを定義する特別な種類のウィジェットです。このコンテキストをそのサブツリー内のすべてのウィジェットに効率的に提供できます。アクセスパターンは、Flutter開発者にとってなじみのあるものに見えるはずです。
final myInheritedWidget = MyInheritedWidget.of(context);
このコンテキストは単なるDartクラスです。したがって、そこに詰め込みたいものは何でも含めることができます。
Style
またはなどの一般的に使用されるFlutterコンテキストの多くは、MediaQuery
レベルに存在するDependedWidgetにすぎませんMaterialApp
。
AliExpressWidgetを使用して上記の例を補足すると、次のようになります。
class MyInheritedWidget extends InheritedWidget {
final int accountId;
final int scopeId;
MyInheritedWidget(accountId, scopeId, child): super(child);
@override
bool updateShouldNotify(MyInheritedWidget old) =>
accountId != old.accountId || scopeId != old.scopeId;
}
class MyPage extends StatelessWidget {
final int accountId;
final int scopeId;
MyPage(this.accountId, this.scopeId);
Widget build(BuildContext context) {
return new MyInheritedWidget(
accountId,
scopeId,
const MyWidget(),
);
}
}
class MyWidget extends StatelessWidget {
const MyWidget();
Widget build(BuildContext context) {
// -
const MyOtherWidget();
...
}
}
class MyOtherWidget extends StatelessWidget {
const MyOtherWidget();
Widget build(BuildContext context) {
final myInheritedWidget = MyInheritedWidget.of(context);
print(myInheritedWidget.scopeId);
print(myInheritedWidget.accountId);
...
注意することが重要です:
- コンストラクターは
const
、これらのウィジェットをキャッシュ可能にするものです。生産性が向上します。 - パラメータが更新されると、新しいパラメータが作成され
MyInheritedWidget
ます。ただし、最初の例とは異なり、サブツリーは再構築されません。代わりに、Flutterは、これInheritedWidget
にアクセスしたウィジェットを追跡する内部レジストリを維持し、このコンテキストを使用するウィジェットのみを再構築します。この例では、ですMyOtherWidget
。 - 向きの変更など、パラメータの変更以外の理由でツリーが再構築された場合でも、コードは新しいツリーを構築できます
InheritedWidget
。ただし、パラメーターは同じままであるため、サブツリー内のウィジェットは通知されません。これが、updateShouldNotify
あなたが実装した関数の目的ですInheritedWidget
。
最後に、グッドプラクティスについて話しましょう。
着用ウィジェットは小さくする必要があります
Flutterはコンテキストのどの部分が更新され、どの部分がウィジェットによって使用されているかを判断できないため、多くのコンテキストでそれらをオーバーロードすると、上記の2番目と3番目の利点が失われます。代わりに:
class MyAppContext {
int teamId;
String teamName;
int studentId;
String studentName;
int classId;
...
}
することを好む:
class TeamContext {
int teamId;
String teamName;
}
class StudentContext {
int studentId;
String studentName;
}
class ClassContext {
int classId;
...
}
constを使用してウィジェットを作成します
constがないと、サブツリーを選択的に再構築することはできません。Flutterは、サブツリー内の各ウィジェットの新しいインスタンスを作成して呼び出し
build()
、特にビルドメソッドが十分に重い場合は、貴重なサイクルを浪費します。
あなたのInheritedWidget
-sの範囲に目を離さないでください
InheritedWidget
-yはウィジェットツリーのルートに配置されます。実際、これがその範囲を決定します。私たちのチームでは、ウィジェットツリーのどこにでもコンテキストを宣言できるのはやり過ぎであることがわかりました。コンテキストウィジェットを制限してScaffold
、子としてのみ(またはその派生物)を受け入れることにしました。このようにして、最も詳細なコンテキストをページレベルにすることができ、2つのスコープを取得します。
- などのアプリケーションレベルのウィジェット
MediaQuery
。これらは、アプリケーションのウィジェットツリーのルートにあるため、アプリケーションの任意のページの任意のウィジェットで使用できます。 MyInheritedWidget
上記の例のようなページレベルのウィジェット。
コンテキストが適用される場所に応じて、どちらかを選択する必要があります。
ページレベルのウィジェットはルートの境界を越えることができません
当たり前のようです。ただし、ほとんどのアプリケーションには複数のレベルのナビゲーションがあるため、これには深刻な影響があります。アプリケーションは次のようになります。
> School App [App Context]
> Student [Student Context]
> Grades
> Bio
> Teacher [Teacher Context]
> Courses
> Bio
これはFlutterが見ているものです:
> School App [App Context]
> Student [Student Context]
> Student Grades
> Student Bio
> Teacher [Teacher Context]
> Teacher Courses
> Teacher Bio
Flutterの観点からは、ナビゲーション階層はありません。各ページ(またはスキャフォールド)は、アプリケーションウィジェットに関連付けられたウィジェットのツリーです。したがって、
Navigator.push
これらのページを使用して表示する場合、親コンテキストを保持するウィジェットを継承しません。上記の例でStudent
は、StudentページからStudentBioページにコンテキストを明示的に渡す必要があります。
コンテキストを渡す方法はいくつかありますが、ルートを昔ながらの方法でパラメーター化することをお勧めします(たとえば、名前付きルートを使用している場合はURLエンコード)。また、親ページのコンテキストを使用せずに、ルートに基づいてページを純粋に構築できるようにします。
ハッピーコーディング!
コースに間に合うように!