Quelle est la relation entre les widgets avec état et sans état dans Flutter?


105

Un widget avec état est défini comme tout widget qui change son état au cours de sa durée de vie. Mais c'est une pratique très courante pour un StatelessWidgetd'avoir un StatefulWidgetcomme l'un de ses enfants. Ne StatelessWidgetdevient- il pas stateful s'il a StatefulWidgetcomme l'un de ses enfants?

J'ai essayé de consulter la documentation dans le cadre du code de StatelessWidget, mais je StatelessWidgetn'ai pas pu comprendre comment un peut avoir Statefulwidgetpour enfants et rester StatelessWidget.

Quelle est la relation et la différence entre les widgets avec état et sans état dans Flutter?


2
Vous pouvez composer votre mise en page à partir de différents types de widgets, mais cela ne signifie pas que vous héritez des caractéristiques de la composition pour affecter chaque widget. Ce que je veux dire, c'est que vous pouvez avoir un conteneur qui est sans état qui a un enfant d'un autre conteneur qui est déclaré comme StatefulWidget ailleurs, l'état du conteneur n'affectera que ce seul composant. Donc, il s'agit d'avoir une composition à partir de différents types de widgets, chaque fonction selon vos besoins.
aziza

1
Pour gâcher les choses encore plus, il y a un 3ème type de widget: InheritedWidget; Ce qui peut faire la StatelessWidgetmise à jour.
Rémi Rousselet

Réponses:


103

Un StatelessWidget ne sera jamais reconstruit par lui-même (mais peut à partir d'événements externes). Un StatefulWidget peut. Telle est la règle d'or.

MAIS tout type de widget peut être repeint à tout moment.

Stateless signifie seulement que toutes ses propriétés sont immuables et que la seule façon de les modifier est de créer une nouvelle instance de ce widget. Cela ne verrouille pas par exemple l'arborescence des widgets.

Mais vous ne devriez pas vous soucier du type de vos enfants. Cela n'a aucun impact sur vous.


11
(Relativement nouveau dans le cadre). Quelle est la différence entre rebuildetrepaint
user462455

Également à partir des commentaires dans le code du framework Flutter, apparemment les StateFulWidgets sont également immuables.
user462455

3
La construction d'un widget est essentiellement un appel à la méthode "build", suivi de la création / mise à jour de la boîte de rendu correspondante; qui est suivi par le processus de peinture. Ce qui imprimera ces boîtes de rendu à l'écran.
Rémi Rousselet

les classes qui héritent de "StatefulWidget" sont immuables. Mais l'état (State <YourWidget>) lui-même est modifiable.
Rémi Rousselet

1
@ RémiRousselet Les widgets avec état et sans état reconstruisent toutes les images, selon flutter.dev/docs/get-started/flutter-for
Matt

82

StatefulWidget contre StatelessWidget.

entrez la description de l'image ici

StatelessWidget - Un widget qui ne nécessite pas d'état mutable.

  • Un widget sans état est un widget qui décrit une partie de l'interface utilisateur en créant une constellation d'autres widgets qui décrivent l'interface utilisateur plus concrètement. Le processus de construction se poursuit de manière récursive jusqu'à ce que la description de l'interface utilisateur soit entièrement concrète (par exemple, se compose entièrement de RenderObjectWidgets, qui décrivent des RenderObjects concrets).

  • Le statelesswidget est utile lorsque la partie de l'interface utilisateur que vous décrivez ne dépend de rien d'autre que des informations de configuration dans l'objet lui-même et du BuildContext dans lequel le widget est gonflé. Pour les compositions qui peuvent changer dynamiquement, par exemple en raison d'un état d'horloge interne, ou en fonction d'un état du système, envisagez d'utiliser StatefulWidget.

class GreenFrog extends StatelessWidget {
  const GreenFrog({ Key key }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(color: const Color(0xFF2DBD3A));
  }
}

StatefulWidget - Un widget dont l'état est modifiable.

  • Les widgets avec état sont utiles lorsque la partie de l'interface utilisateur que vous décrivez peut changer dynamiquement.

Lorsque Flutter construit un StatefulWidget, il crée un objet State. Cet objet est l'endroit où tout l'état mutable de ce widget est conservé.

Le concept d'État est défini par deux choses:

1) Les données utilisées par le widget peuvent changer.

2) Les données ne peuvent pas être lues de manière synchrone lorsque le widget est construit. (Tous les états doivent être établis au moment où la méthode de construction est appelée).

Cycle de vie StatefulWidget

Le cycle de vie comprend les étapes simplifiées suivantes:

  1. createState () - Lorsque Flutter est invité à créer un StatefulWidget, il appelle immédiatement createState().
  • Crée l'état mutable pour ce widget à un emplacement donné dans l'arborescence.

  • Les sous-classes doivent remplacer cette méthode pour renvoyer une instance nouvellement créée de leur sous-classe State associée:

@override
_MyState createState() => _MyState();
  1. monté == true - Tous les widgets ont une this.mountedpropriété booléenne . Cela devient vrai lorsque le buildContextest attribué. C'est une erreur d'appeler setStatelorsqu'un widget est démonté. Si cet objet State est actuellement dans une arborescence.
  • Après avoir créé un objet State et avant l'appel initState, le framework «monte» l'objet State en l'associant à un
    BuildContext. L'objet State reste monté jusqu'à l'
    appel du framework dispose(), après quoi le framework ne demandera plus jamais à l'
    objet State de se reconstruire.

  • C'est une erreur d'appeler setState sauf si monté est vrai.

bool get mounted => _element != null;
  1. initState () - C'est la première méthode appelée lors de la création du widget (après le constructeur de classe, bien sûr).

initStateest appelée une et une seule fois. Il doit appelersuper.initState().

  • Initialisez les données qui reposent sur le BuildContext spécifique pour l'instance créée du widget.

  • Initialisez les propriétés qui reposent sur ces widgets «parents» dans l'arborescence.

  • Abonnez-vous à Streams ChangeNotifiersou à tout autre objet susceptible de modifier les données de ce widget.

@override
initState() {
  super.initState();
  // Add listeners to this class
  cartItemStream.listen((data) {
    _updateWidget(data);
  });
}
  1. didChangeDependencies () - Appelé lorsqu'une dépendance de cet objet State change.
  • Cette méthode est également appelée immédiatement après initState. Il est prudent d'appeler à BuildContext.inheritFromWidgetOfExactTypepartir de cette méthode.

  • Les sous-classes remplacent rarement cette méthode car le framework appelle toujours build après les modifications de dépendance. Certaines sous-classes remplacent cette méthode car elles doivent effectuer un travail coûteux (par exemple, des récupérations de réseau) lorsque leurs dépendances changent, et ce travail serait trop coûteux à faire pour chaque construction.

@protected
@mustCallSuper
void didChangeDependencies() { }
  1. build () - Décrit la partie de l'interface utilisateur représentée par le widget.

Le framework appelle cette méthode dans un certain nombre de situations différentes:

  • Après avoir appelé initState.
  • Après avoir appelé didUpdateWidget.
  • Après avoir reçu un appel à setState.
  • Après une dépendance de cet objet State change (par exemple, un InheritedWidget référencé par les modifications de construction précédentes).
  • Après avoir appelé disable, puis réinséré l'objet State dans l'arborescence à un autre emplacement.
  • Le framework remplace le sous-arbre sous ce widget par le widget retourné par cette méthode, soit en mettant à jour le sous-arbre existant, soit en supprimant le sous-arbre et en gonflant un nouveau sous-arbre, selon que le widget retourné par cette méthode peut mettre à jour la racine du sous-arbre existant , tel que déterminé par l'appel Widget.canUpdate.

  • En général, les implémentations renvoient une constellation nouvellement créée de widgets configurés avec les informations du constructeur de ce widget, le BuildContext donné et l'état interne de cet objet State.

@override
  Widget build(BuildContext context, MyButtonState state) {
    ... () { print("color: $color"); } ...
  }
  1. didUpdateWidget () - Appelé chaque fois que la configuration du widget change.
  • Si le widget parent se reconstruit et demande que cet emplacement dans l'arborescence se mette à jour pour afficher un nouveau widget avec le même type d'exécution et Widget.key, le framework mettra à jour la propriété widget de cet objet State pour faire référence au nouveau widget, puis l'appellera méthode avec le widget précédent comme argument.

  • Remplacez cette méthode pour répondre lorsque le widget change (par exemple, pour démarrer des animations implicites).

  • Le framework appelle toujours build après avoir appelé didUpdateWidget, ce qui signifie que tous les appels à setState dans didUpdateWidget sont redondants.

@mustCallSuper
@protected
void didUpdateWidget(covariant T oldWidget) { }
  1. setState () - Chaque fois que vous modifiez l'état interne d'un objet State, apportez le changement dans une fonction que vous passez à setState:
  • L'appel de setState notifie au framework que l'état interne de cet objet a changé d'une manière qui pourrait avoir un impact sur l'interface utilisateur dans cette sous-arborescence, ce qui oblige le framework à planifier une génération pour
    cet objet State.

  • Si vous modifiez simplement l'état directement sans appeler setState , le framework peut ne pas planifier une génération et l'interface utilisateur de cette sous-arborescence peut ne pas être mise à jour pour refléter le nouvel état.

setState(() { _myState = newValue });
  1. deactivate () - Deactivate est appelé lorsque State est supprimé de l'arborescence, mais il peut être réinséré avant la fin du changement de cadre actuel. Cette méthode existe essentiellement parce que les objets State peuvent être déplacés d'un point dans une arborescence à un autre.
  • Le framework appelle cette méthode chaque fois qu'il supprime cet objet State de l'arborescence. Dans certains cas, le cadre réinsère l'objet State dans une autre partie de l'arborescence (par exemple, si le sous-arbre contenant cet objet State est greffé d'un emplacement dans l'arborescence à un autre). Si cela se produit, le framework s'assurera qu'il appelle build pour donner à l'objet State une chance de s'adapter à son nouvel emplacement dans l'arborescence. Si le framework réinsère ce sous-arbre, il le fera avant la fin de l'image d'animation dans laquelle le sous-arbre a été supprimé de l'arborescence. Pour cette raison, les objets State peuvent différer la libération de la plupart des ressources jusqu'à ce que l'infrastructure appelle leur méthode dispose.

Ceci est rarement utilisé.

@protected
@mustCallSuper
void deactivate() { }
  1. dispose () - Appelé lorsque cet objet est supprimé définitivement de l'arborescence.
  • Le framework appelle cette méthode lorsque cet objet State ne sera plus jamais généré. Après les appels du framework dispose(), l'objet State est considéré comme non monté et la propriété montée est false. L'appel de setState à ce stade est une erreur. Cette étape du cycle de vie est terminale: il n'y a aucun moyen de remonter un objet State qui a été supprimé.

  • Les sous-classes doivent remplacer cette méthode pour libérer toutes les ressources conservées par cet objet (par exemple, arrêter toutes les animations actives).

@protected
@mustCallSuper
void dispose() {
  assert(_debugLifecycleState == _StateLifecycle.ready);
  assert(() { _debugLifecycleState = _StateLifecycle.defunct; return true; }());
}

entrez la description de l'image ici

Pour plus d'informations, cliquez ici , ici


26

À partir de la documentation sur flutter.io :

... La chose importante à noter ici est que les widgets Stateless et Stateful se comportent de la même manière. Ils reconstruisent chaque image, la différence est que le StatefulWidget a un objet State qui stocke les données d'état à travers les images et les restaure.

En cas de doute, souvenez-vous toujours de cette règle: si un widget change (l'utilisateur interagit avec lui, par exemple), il est avec état. Cependant, si un enfant réagit au changement, le parent contenant peut toujours être un widget sans état si le parent ne réagit pas au changement.


14

Comme mentionné dans les documents Flutter

À quoi ça sert?

Certains widgets sont avec état et certains sont sans état. Si un widget change - l'utilisateur interagit avec lui, par exemple - il est avec état. L'état d'un widget se compose de valeurs qui peuvent changer, comme la valeur actuelle d'un curseur ou si une case est cochée. L'état d'un widget est stocké dans un objet State, séparant l'état du widget de son apparence. Lorsque l'état du widget change, l'objet d'état appelle setState (), indiquant au framework de redessiner le widget.

Un widget sans état n'a aucun état interne à gérer. Icon, IconButton et Text sont des exemples de widgets sans état, qui sous-classe StatelessWidget.

Un widget avec état est dynamique. L'utilisateur peut interagir avec un widget avec état (en tapant dans un formulaire ou en déplaçant un curseur, par exemple), ou il change avec le temps (peut-être qu'un flux de données entraîne la mise à jour de l'interface utilisateur). Checkbox, Radio, Slider, InkWell, Form et TextField sont des exemples de widgets avec état, qui sous-classe StatefulWidget.

https://flutter.io/tutorials/interactive/#stateful-stateless


10

L'état est une information qui (1) peut être lue de manière synchrone lorsque le widget est construit et (2) peut changer pendant la durée de vie du widget. Il est de la responsabilité de l'implémenteur du widget de s'assurer que l'État est rapidement notifié lorsqu'un tel état change, en utilisant State.setState.

StatefulWidget :

Un widget avec état est un widget qui décrit une partie de l'interface utilisateur en créant une constellation d'autres widgets qui décrivent l'interface utilisateur plus concrètement. Le processus de construction se poursuit de manière récursive jusqu'à ce que la description de l'interface utilisateur soit entièrement concrète (par exemple, se compose entièrement de RenderObjectWidgets, qui décrivent des RenderObjects concrets).

Les widgets avec état sont utiles lorsque la partie de l'interface utilisateur que vous décrivez peut changer dynamiquement, par exemple en raison d'un état interne piloté par l'horloge ou en fonction d'un état du système. Pour les compositions qui dépendent uniquement des informations de configuration de l'objet lui-même et du BuildContext dans lequel le widget est gonflé, envisagez d'utiliser StatelessWidget.

Les instances StatefulWidget elles-mêmes sont immuables et stockent leur état mutable soit dans des objets State séparés créés par la méthode createState, soit dans des objets auxquels cet State souscrit, par exemple des objets Stream ou ChangeNotifier, auxquels les références sont stockées dans les champs finaux du StatefulWidget lui-même.

StatelessWidget :

Un widget sans état est un widget qui décrit une partie de l'interface utilisateur en créant une constellation d'autres widgets qui décrivent l'interface utilisateur plus concrètement. Le processus de construction se poursuit de manière récursive jusqu'à ce que la description de l'interface utilisateur soit entièrement concrète (par exemple, se compose entièrement de RenderObjectWidgets, qui décrivent des RenderObjects concrets).

Les widgets sans état sont utiles lorsque la partie de l'interface utilisateur que vous décrivez ne dépend de rien d'autre que des informations de configuration dans l'objet lui-même et du BuildContext dans lequel le widget est gonflé. Pour les compositions qui peuvent changer dynamiquement, par exemple en raison d'un état d'horloge interne, ou en fonction d'un état du système, envisagez d'utiliser StatefulWidget.


9

Les widgets sans état sont des widgets statiques. Il vous suffit de passer quelques propriétés avant d'initialiser les widgets sans état. Ils ne dépendent d'aucun changement de données ni d'aucun changement de comportement. Par exemple. Text, Icon, RaisedButton sont des widgets sans état.

Les widgets avec état sont des widgets dynamiques, ils peuvent être mis à jour pendant l'exécution en fonction de l'action de l'utilisateur ou de la modification des données. Si un widget peut changer son état pendant l'exécution, il sera un widget avec état.

Modifier 15/11/2018

Les widgets sans état peuvent être rendus si les données d'entrée / externes ont été modifiées (les données externes étant des données transmises via le constructeur). Étant donné que les widgets sans état n'ont pas d'état, ils seront rendus une fois et ne seront pas mis à jour eux-mêmes, mais ne seront mis à jour que lorsque les données externes changeront.

Alors que les widgets avec état ont un état interne et peuvent être rendus si les données d'entrée changent ou si l'état du widget change.

Les widgets sans état et avec état ont un cycle de vie différent.


Même après avoir passé une nouvelle donnée de l'extérieur vers un Statelesswidget, nous pouvons également les modifier au moment de l'exécution, mais cela ne s'appelle pas Statefulwidget (contrairement à votre dernière ligne).
CopsOnRoad

Pouvez-vous expliquer comment un widget sans état peut "être mis à jour lorsque des données externes changent"? (Avec "les données externes étant des données passées par le constructeur".) Le constructeur ne sera-t-il pas seulement appelé une fois? Comment les données sont-elles passées par le constructeur?
user1596274

8

Je peux penser à une analogie très simple. Vous avez un meuble avec des livres, des décorations et une télévision. Le mobilier est apatride, il ne fait rien ne bouge pas. Sur le téléviseur, de l'autre côté, vous pouvez l'allumer, l'éteindre, changer de chaîne, lire un film s'il y a un DVD attaché, etc. Le téléviseur a un état interne qui affecte la façon dont il se comporte. Dans les meubles, vous n'avez aucun état. La présence du téléviseur dans le meuble n'y ajoute pas un état. J'espère que cela t'aides.


Cela ne répond pas à la question spécifique du demandeur.
Ésaïe

1
C'est une excellente analogie!
William Terrill le

6

Réponse à la question Stack Overflow - état vs apatridie .

Dans Flutter, la différence est que les widgets sans état peuvent être définis uniquement par tous les arguments du constructeur. Si vous créez deux widgets sans état en utilisant les mêmes arguments, ils seront identiques.

Un widget avec état, cependant, n'est pas nécessairement le même qu'un autre construit avec les mêmes arguments de constructeur. Cela pourrait être dans un état différent.
En fait, un widget avec état est lui-même immuable (sans état), mais Flutter gère un objet d' état séparé et l'associe au widget, comme expliqué dans la documentation StatefulWidget . Cela signifie que lorsque Flutter reconstruit un widget avec état, il vérifiera s'il doit réutiliser un objet d'état précédent et, si vous le souhaitez, attachera cet objet d'état au widget.

Le widget parent est sans état car il ne se soucie pas de l'état de son enfant. L'enfant avec état lui-même (ou techniquement Flutter) prendra soin de son propre état.
À un niveau élevé, je conviens que cela rend le widget parent avec état, car deux parents peuvent contenir deux enfants avec des états différents et donc être techniquement différents eux-mêmes. Mais du point de vue de Flutter, il construit le widget parent sans se soucier de l'état et ce n'est que lors de la construction que l'enfant considérera son état complet.


5

Que sont les widgets avec état et sans état?

TL; DR: Un widget qui vous permet d'actualiser l'écran est un widget avec état. Un widget qui ne l'est pas est sans état.

Plus en détail, un widget dynamique dont le contenu peut changer doit être un widget avec état. Un widget sans état ne peut changer de contenu que lorsque les paramètres sont modifiés et doit donc être effectué au-dessus du point de son emplacement dans la hiérarchie des widgets. Un écran ou un widget contenant du contenu statique doit être un widget sans état, mais pour modifier le contenu, il doit être avec état.

J'ai trouvé ce contenu relatif sur une histoire médiatique intéressante. Vous êtes les bienvenus!


4

Stateless : l'état du widget crée UNE SEULE FOIS, puis il peut mettre à jour les valeurs mais pas l'état explicitement. Cela ressort également clairement de leur structure. C'est pourquoi il n'a qu'une seule classe qui s'étend avec StatelessWidget. Donc, si je dis, ils ne peuvent plus jamais réexécuter la build()méthode.

Avec état : les widgets peuvent mettre à jour leur état (localement) et leurs valeurs plusieurs fois lors du déclenchement d'un événement . C'est la raison pour laquelle la mise en œuvre est également différente. En cela, nous avons 2 classes, l'une est StatefulWidgetet l'autre est son gestionnaire d'implémentation d'état, c'est-à-dire State<YourWidget>. Donc, si je dis, ils peuvent réexécuter la build()méthode encore et encore en fonction des événements déclenchés.

Le diagramme ci-dessous vous aidera.

entrez la description de l'image ici


1

Lorsque vous écrivez une application, vous créez généralement de nouveaux widgets qui sont des sous-classes de StatelessWidget ou StatefulWidget

Voici quelques différences entre StatelessWidgetet StatefulWidgetwidgets:

Widget sans état:

  1. Un widget qui a un état immuable.
  2. Les widgets sans état sont des widgets statiques.
  3. Ils ne dépendent d'aucun changement de données ni d'aucun changement de comportement.
  4. Les widgets sans état n'ont pas d'état, ils seront rendus une fois et ne seront pas mis à jour eux-mêmes, mais ne seront mis à jour que lorsque les données externes changeront.
  5. Par exemple: Text, Icon, RaisedButtonsont Apatrides Widgets.

Widget sans état:

  1. Un widget qui a un état mutable.
  2. Les widgets avec état sont des widgets dynamiques.
  3. Ils peuvent être mis à jour pendant l'exécution en fonction de l'action de l'utilisateur ou de la modification des données.
  4. Les widgets avec état ont un état interne et peuvent être rendus si les données d'entrée changent ou si l'état du widget change.
  5. Par exemple: Checkbox, Radio Button, Slidersont Stateful Widgets

1

avertissement: - a commencé à travailler sur le flutter de la semaine dernière :)

Le widget sans état et avec état a son propre cycle de vie pour créer et mettre à jour l'interface utilisateur. Cependant, vous pouvez utiliser stateless ou statefull pour rendre l'interface utilisateur, mais pratiquement statefull est plus pratique lorsque l'interface utilisateur est totalement ou partiellement dépendante des données externes (comme - rendre une liste à l'aide de l'api) tout en utilisant un widget sans état pour rendre une interface utilisateur statique comme n'importe quel écran d'entrée est une bonne pratique.


1
Je pense que l'auteur voulait dire le contraire: · D
Roc Boronat

0

En termes simples:

Comme nous le savons, chaque widget est une vue dans le flottement. Qui a ses propres classes. Lorsque nous utilisons ces classes, nous en créons un objet. Nous donnons des valeurs à leurs différentes variables / propriétés. Ex. Nous créons un widget de texte afin de pouvoir lui donner une chaîne, une couleur, une taille de police, une famille de polices. Donc en donnant ceci, nous définissons ses propriétés lors de sa création. Jusqu'à présent, les widgets sans état ou avec état sont les mêmes mais,

Lorsque nous voulons changer / mettre à jour ses propriétés (disons String ou Color) encore et encore par la suite, alors il devrait être un widget avec état.

Et lorsque nous ne voulons pas modifier ses propriétés après avoir défini la première fois, il s'agit d'un widget sans état.

cela signifie que nous nous soucions des données que le widget contient / contrôle / affiche.

Donc Stateless est moins de données et Stateful est plein de données.

Maintenant, si vous définissez une classe qui est sans état, cela signifie que cette classe ne se soucie pas / contient des variables ou dit des données dans sa propre classe, c'est-à-dire au niveau de la classe, mais elle pourrait avoir un autre widget / classe en elle qui se soucie des données, c'est-à-dire qu'elle est avec état . Cela n'a donc aucun impact l'un sur l'autre.

Veuillez me corriger si je me trompe ici.


0

Que sont les widgets avec état et sans état?

Widget sans état: les widgets sans état sont créés uniquement lorsqu'il s'agit de modifications parentes.

Widgets avec état: les widgets d'état complets contiennent l'état du widget et peuvent être reconstruits lorsque l'état change.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.