Übergeben von Daten an ein Stateful Widget

112

Ich frage mich, wie die empfohlene Methode zum Übergeben von Daten an ein zustandsbehaftetes Widget beim Erstellen empfohlen wird.

Die zwei Stile, die ich gesehen habe, sind:

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;
  }
}

Diese Methode behält einen Wert sowohl in ServerInfoals auch bei _ServerInfoState, was etwas verschwenderisch erscheint.

Die andere Methode ist zu verwenden 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;
    }
}

Dies scheint etwas rückwärts zu sein, da der Status nicht mehr _ServerInfoSateim Widget gespeichert wird, sondern im Widget.

Gibt es dafür eine bewährte Methode?

Mojachiee
quelle
3
Der Konstruktor kann aufServerInfo(this._server);
Günter Zöchbauer
Diese Fragen wurden früher gestellt: stackoverflow.com/questions/50428708/…
Blasanka
Diese Antwort wird einen Monat vor dieser hinzugefügt: stackoverflow.com/questions/50428708/…
Blasanka
Beantwortet das deine Frage?
Übergeben Sie

Antworten:

228

Übergeben Sie keine Parameter an Stateden Konstruktor. Sie sollten nur mit auf diese zugreifen this.widget.myField.

Das Bearbeiten des Konstruktors erfordert nicht nur viel manuelle Arbeit. es bringt nichts. Es gibt keinen Grund, alle Felder von zu duplizieren Widget.

EDIT:

Hier ist ein Beispiel:

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")
    );
  }
}
Rémi Rousselet
quelle
23
Ein weiterer Kommentar: Alles, was Sie über den Konstruktor an ein State-Objekt übergeben, wird niemals aktualisiert!
Jonah Williams
4
Und hier bin ich und verstehe den Kommentar nicht. "Übergeben Sie keine Parameter mit dem Konstruktor an State". Wie übergebe ich Parameter an den Staat?
KhoPhi
6
@Rexford Statebereits als Zugriff auf alle Eigenschaften Statefulvon über das widgetFeld.
Rémi Rousselet
4
@ RémiRousselet Was ist, wenn ich ein Textfeld mit foo vorab ausfüllen und dem Benutzer dennoch erlauben möchte, es zu bearbeiten? Sollte ich dem Staat noch eine weitere foo-Eigenschaft hinzufügen?
Sagte Saifi
1
@ user6638204 Sie können eine weitere foo-Eigenschaft im Status erstellen und den Status überschreiben void initState(), um den Anfangswert festzulegen . Aktivieren Sie diese Thread- Option C als Beispiel.
Joseph Cheng
30

Am besten übergeben Sie keine Parameter mit dem Konstruktor an die State-Klasse. Sie können einfach in der State-Klasse mit zugreifen widget.myField.

Beispielsweise

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); 
  }
}

Übergeben Sie Ihre Daten, wenn Sie auf dem Bildschirm navigieren:

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

Eine weitere Antwort, die auf der Antwort von @ RémiRousselet und der Frage von @ user6638204 aufbaut, wenn Sie Anfangswerte übergeben und diese später noch aktualisieren möchten:

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);
  }
}
Nicolas Dion-Bouchard
quelle
7
Wir können initState direkt verwenden, um so etwas wie foo = widget.foo zu tun. Es ist keine Übergabe an den Konstruktor erforderlich
Aqib
Wie kann man das argumentieren?
Steev James
@SteevJames das Widget MyStatefulhat einen optionalen benannten Parameter (Eigenschaft), den Sie dieses Widget erstellen können, indem SieMyStateful(foo: "my string",)
Kirill Karmazin
@Aqib the initStatelöst im folgenden Szenario kein Problem: Sie haben beispielsweise Ihr Statefull-Widget mit leeren Parametern erstellt und warten darauf, dass Ihre Daten geladen werden. Wenn die Daten geladen sind, möchten Sie Ihr Statefull-Widget mit den neuen Daten aktualisieren. In diesem Fall wird MyStatefull (newData) initState()nicht aufgerufen, wenn Sie MyStatefull (newData) aufrufen . In diesem Fall didUpdateWidget(MyStatefull oldWidget)wird aufgerufen und Sie müssten Ihre Daten aus Argument oldWidget.getData()mit vergleichen widget.dataund wenn es nicht dasselbe ist - rufen Sie setState()auf, um das Widget neu zu erstellen.
Kirill Karmazin
1
@ kirill-karmazin Können Sie die Stateless-Widget-Lösung näher erläutern? Was würdest du stattdessen verwenden? Ist es eine Best Practice des Flutter-Teams? Vielen Dank
camillo777
4

Zum Übergeben von Anfangswerten (ohne etwas an den Konstruktor zu übergeben)

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);
  }
}
Daksh Shah
quelle