Flutter: comment utiliser correctement un Widget hérité?

Quelle est la bonne façon d'utiliser Unwidget hérité? Jusqu'à présent, j'ai compris qu'il vous donne la chance de propager des données le long de L'arbre Widget. Dans l'extrême si vous mettez est comme RootWidget il sera accessible à partir de tous les Widgets dans l'arbre sur toutes les Routes, ce qui est bien parce que d'une certaine façon je dois rendre mon ViewModel/modèle accessible pour mes Widgets sans avoir à recourir à des globals ou des Singletons.

mais le widget hérité est immuable, alors comment puis-je le mettre à jour? Et plus important encore comment sont mes Widgets D'État déclenchés pour reconstruire leurs sous-trées?

malheureusement la documentation est ici très peu claire et après discussion avec beaucoup personne ne semble vraiment savoir quelle est la bonne façon de l'utiliser.

j'ajoute une citation de Brian Egan:

Oui, je le vois comme un moyen de propager les données en bas de l'arbre. Ce que je trouve déroutant, à partir de l'API docs:

"les widgets hérités, lorsqu'ils sont référencés de cette façon, causeront la consommation de reconstruire lorsque le widget hérité change d'état."

quand j'ai lu ceci pour la première fois, j'ai pensé:

je pourrais remplir quelques données dans le widget hérité et le muter plus tard. Quand cette mutation se produit, il va reconstruire tous les Widgets que référence de mon InheritedWidget Ce que j'ai trouvé:

pour muter L'État D'un widget hérité, vous devez envelopper il dans un État de Widget vous muter alors réellement l'état de la StatefulWidget et pass cette donnée jusqu'à la Widget héritée, qui donne les données à tous les enfants. Toutefois, dans ce cas, il semble reconstruire l'arbre entier sous le StatefulWidget, pas juste les Widgets qui font référence au widget hérité. Est-ce exact? Ou va-t-il en quelque sorte savoir comment sauter les Widgets qui font référence à la Héritedwidget si updateShouldNotify retourne false?

21
demandé sur Günter Zöchbauer 2018-03-26 15:47:46

1 réponses

le problème vient de votre citation, qui est incorrecte.

comme vous l'avez dit, les widgets hérités sont, comme les autres widgets, immuables. Par conséquent, ils ne sont pas mise à jour. Ils sont créés de nouveau.

Le truc, c'est : InheritedWidget est juste un simple widget qui ne fait rien d'autre que de contenir des données. Il n'a aucune logique de mise à jour ou autre. Mais, comme tous les autres widgets, il est associé à un Element. Et devinez quoi ? Cette chose est mutable et flutter le réutilisera dans la mesure du possible !

Le corrigé citation serait :

InheritedWidget, lorsqu'il est référencé de cette façon, va provoquer le consommateur à reconstruire lorsque InheritedWidget associé à un InheritedElement changements.

Il y a un grand discours sur la façon widgets/elements/renderbox sont branché ensemble. Mais en bref, ils sont comme ceci (à gauche est votre widget typique, le milieu est "d'éléments", et la droite sont des "render cases") :

enter image description here

Le truc, c'est : Lorsque vous instanciez un nouveau widget ; flutter va le comparer à l'ancien. Réutiliser C'est" Element", qui pointe vers une RenderBox. Et muter le renderbox propriétés.


D'accord, mais comment cela répond - il à ma question ?

eh Bien, c'est facile. Lors de l'instanciation d'un InheritedWidget, et puis l'appel de context.inheritedWidgetOfExactType (ou MyClass.of ce qui est fondamentalement le même) ; ce qui est sous-entendu est qu'il écoutera le Element associé à votre InheritedWidget. Et à chaque fois que Element obtient un nouveau widget, il va forcer le rafraîchissement de tous les widgets qui ont appelé la méthode précédente.

en bref, quand vous remplacez unInheritedWidget avec un tout nouveau ; flutter verra qu'il a changé. Et le notifiera les widgets liés d'une modification potentielle.

Si vous avez compris tout, vous devriez avoir déjà deviné la solution:

Enveloppez votre InheritedWidget dans un StatefulWidget qui permettra de créer une nouvelle marque InheritedWidget chaque fois que quelque chose a changé ! Dans cette situation, il est recommandé pour votre InheritedWidget données de fait juste l'exemple de votre StatefulWidget et ensuite faire InheritedWidget privé. Pour éviter le copier-coller inutile et les erreurs possibles.

Le résultat final réel de code :

class MyInherited extends StatefulWidget {
  Widget child;

  MyInherited({this.child});

  @override
  MyInheritedState createState() => new MyInheritedState();

  static MyInheritedState of(BuildContext context) {
    return (context.inheritFromWidgetOfExactType(_MyInherited) as _MyInherited).data;
  }
}

class MyInheritedState extends State<MyInherited> {
  String _myField;
  // only expose a getter to prevent bad usage
  String get myField => _myField;

  void onMyFieldChange(String newValue) {
    setState(() {
      _myField = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new _MyInherited(
      data: this,
      child: widget.child,
    );
  }
}

/// Only has MyInheritedState as field.
class _MyInherited extends InheritedWidget {
  final MyInheritedState data;

  _MyInherited({Key key, this.data, Widget child}) : super(key: key, child: child);

  @override
  bool updateShouldNotify(_MyInherited old) {
    return true;
  }
}

Mais est-ce que créer un nouveau widget en héritage ne reconstruirait pas l'arbre entier ?

Non Ce ne sera pas nécessairement. Comme votre nouveau widget hérité peut potentiellement avoir le même enfant qu'avant. Et par exact, je veux dire la même instance. Les Widgets qui ont la même instance qu'avant ne reconstruisent pas.

et dans la plupart des cas (ayant un widget hérité à la racine de votre application), le widget hérité est constant. Donc pas de reconstruction inutile.

28
répondu Rémi Rousselet 2018-10-01 14:34:32