Passer des données à un widget avec état


114

Je me demande quelle est la manière recommandée de transmettre des données à un widget avec état, lors de sa création.

Les deux styles que j'ai vus sont:

class ServerInfo extends StatefulWidget {

  Server _server;

  ServerInfo(Server server) {
    this._server = server;
  }

  @override
    State<StatefulWidget> createState() => new _ServerInfoState(_server);
}

class _ServerInfoState extends State<ServerInfo> {
  Server _server;

  _ServerInfoState(Server server) {
    this._server = server;
  }
}

Cette méthode conserve une valeur à la fois dans ServerInfoet _ServerInfoState, ce qui semble un peu inutile.

L'autre méthode consiste à utiliser widget._server:

class ServerInfo extends StatefulWidget {

  Server _server;

  ServerInfo(Server server) {
    this._server = server;
  }

  @override
    State<StatefulWidget> createState() => new _ServerInfoState();
}

class _ServerInfoState extends State<ServerInfo> {
  @override
    Widget build(BuildContext context) {
      widget._server = "10"; // Do something we the server value
      return null;
    }
}

Cela semble un peu à l'envers car l'état n'est plus stocké dans _ServerInfoSatemais plutôt dans le widget.

Existe-t-il une meilleure pratique pour cela?


3
Le constructeur peut être réduit àServerInfo(this._server);
Günter Zöchbauer

Cette question a été posée plus tôt: stackoverflow.com/questions/50428708/…
Blasanka


Cette réponse est ajoutée un mois avant celle-ci: stackoverflow.com/questions/50428708/…
Blasanka

Réponses:


232

Ne transmettez pas de paramètres à l' Stateutilisation de son constructeur. Vous ne devez y accéder qu'en utilisant this.widget.myField.

Non seulement l'édition du constructeur nécessite beaucoup de travail manuel; ça n'apporte rien. Il n'y a aucune raison de dupliquer tous les champs de Widget.

ÉDITER :

Voici un exemple:

class ServerIpText extends StatefulWidget {
  final String serverIP;

  const ServerIpText ({ Key key, this.serverIP }): super(key: key);

  @override
  _ServerIpTextState createState() => _ServerIpTextState();
}

class _ServerIpTextState extends State<ServerIpText> {
  @override
  Widget build(BuildContext context) {
    return Text(widget.serverIP);
  }
}

class AnotherClass extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ServerIpText(serverIP: "127.0.0.1")
    );
  }
}

23
Un autre commentaire, tout ce que vous passez à un objet State via le constructeur ne sera jamais mis à jour!
Jonah Williams

4
Et me voilà et je ne comprends pas le commentaire. "Ne passez pas de paramètres à State en utilisant son constructeur". Alors, comment puis-je transmettre des paramètres à l'État?
KhoPhi

6
@Rexford Statedéjà comme accès à toutes les propriétés de Statefulen utilisant le widgetchamp.
Rémi Rousselet

4
@ RémiRousselet Que faire si je veux utiliser foo pour préremplir un champ de texte, tout en autorisant l'utilisateur à le modifier. Dois-je également ajouter une autre propriété foo dans l'état?
Said Saifi le

1
@ user6638204 Vous pouvez créer une autre propriété foo dans l'état et remplacer l' void initState()état pour définir la valeur initiale. Cochez cette option de filetage C comme exemple.
Joseph Cheng

31

Le meilleur moyen est de ne pas transmettre de paramètres à la classe State en utilisant son constructeur. Vous pouvez facilement accéder à la classe State en utilisant widget.myField.

Par exemple

class UserData extends StatefulWidget {
  final String clientName;
  final int clientID;
  const UserData(this.clientName,this.clientID);

  @override
  UserDataState createState() => UserDataState();
}

class UserDataState extends State<UserData> {
  @override
  Widget build(BuildContext context) {
    // Here you direct access using widget
    return Text(widget.clientName); 
  }
}

Transmettez vos données lorsque vous naviguez sur l'écran:

 Navigator.of(context).push(MaterialPageRoute(builder: (context) => UserData("WonderClientName",132)));

8

Une autre réponse, en s'appuyant sur la réponse de @ RémiRousselet et pour la question de @ user6638204, si vous voulez passer les valeurs initiales et pouvoir encore les mettre à jour dans l'état plus tard:

class MyStateful extends StatefulWidget {
  final String foo;

  const MyStateful({Key key, this.foo}): super(key: key);

  @override
  _MyStatefulState createState() => _MyStatefulState(foo: this.foo);
}

class _MyStatefulState extends State<MyStateful> {
  String foo;

  _MyStatefulState({this.foo});

  @override
  Widget build(BuildContext context) {
    return Text(foo);
  }
}

7
Nous pouvons directement utiliser initState pour faire quelque chose comme foo = widget.foo, aucun passage au constructeur n'est requis
Aqib

Comment passer un argument à cela?
Steev James

@SteevJames le widget MyStatefula un paramètre nommé facultatif (propriété) que vous pouvez créer ce widget en appelantMyStateful(foo: "my string",)
Kirill Karmazin

@Aqib the initStatene résout pas un problème dans le scénario suivant: par exemple, vous avez créé votre widget Statefull avec des paramètres vides et vous attendez que vos données se chargent. Lorsque les données sont chargées, vous souhaitez mettre à jour votre widget Statefull avec les données fraîches et dans ce cas, lorsque vous appelez MyStatefull (newData), il ne initState()sera pas appelé! Dans ce cas, didUpdateWidget(MyStatefull oldWidget)il sera appelé et vous devrez comparer vos données d'argument oldWidget.getData()avec widget.dataet si ce n'est pas la même chose - appelez setState()pour reconstruire le widget.
Kirill Karmazin

1
@ kirill-karmazin pouvez-vous en dire plus sur la solution de widget sans état? qu'utiliseriez-vous à la place? Est-ce une meilleure pratique de l'équipe Flutter? Merci
camillo777

4

Pour passer des valeurs initiales (sans rien passer au constructeur)

class MyStateful extends StatefulWidget {
  final String foo;

  const MyStateful({Key key, this.foo}): super(key: key);

  @override
  _MyStatefulState createState() => _MyStatefulState();
}

class _MyStatefulState extends State<MyStateful> {
  @override
  void initState(){
    super.initState();
    // you can use this.widget.foo here
  }

  @override
  Widget build(BuildContext context) {
    return Text(foo);
  }
}
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.