Passaggio di dati a un widget con stato


114

Mi chiedo quale sia il modo consigliato per passare i dati a un widget con stato durante la creazione.

I due stili che ho visto sono:

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

Questo metodo mantiene un valore sia in ServerInfoche _ServerInfoState, il che sembra un po 'dispendioso.

L'altro metodo consiste nell'usare 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;
    }
}

Questo sembra un po 'indietro poiché lo stato non è più memorizzato _ServerInfoSatema invece nel widget.

Esiste una best practice per questo?


3
Il costruttore può essere ridotto aServerInfo(this._server);
Günter Zöchbauer

Questa discussione è stato chiesto in precedenza: stackoverflow.com/questions/50428708/...
Blasanka


Questa risposta viene aggiunta un mese prima questo: stackoverflow.com/questions/50428708/...
Blasanka

Risposte:


232

Non passare parametri Stateall'uso del suo costruttore. Dovresti accedervi solo usando this.widget.myField.

Non solo la modifica del costruttore richiede molto lavoro manuale; non porta niente. Non c'è motivo di duplicare tutti i campi di Widget.

MODIFICARE :

Ecco un esempio:

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 ulteriore commento, tutto ciò che passi a un oggetto State tramite il costruttore non verrà mai aggiornato!
Jonah Williams

4
Ed eccomi qui e non capisco il commento. "Non passare parametri a State usando il suo costruttore". Allora come si passano i parametri allo Stato?
KhoPhi

6
@Rexford Stategià come accesso a tutte le proprietà di Statefulutilizzando il widgetcampo.
Rémi Rousselet il

4
@ RémiRousselet E se volessi usare pippo per precompilare un campo di testo e consentire comunque all'utente di modificarlo. Devo aggiungere anche un'altra proprietà foo nello stato?
Ha detto Saifi il

1
@ user6638204 Puoi creare un'altra proprietà foo nello stato e sovrascrivere lo void initState()stato per impostare il valore iniziale. Controlla questa opzione di thread C come esempio.
Joseph Cheng il

31

Il modo migliore è non passare i parametri alla classe State usando il suo costruttore. Puoi accedere facilmente alla classe State usando widget.myField.

Per esempio

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

Passa i tuoi dati quando navighi nella schermata:

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

8

Un'altra risposta, basata sulla risposta di @ RémiRousselet e per la domanda di @ user6638204, se vuoi passare i valori iniziali ed essere comunque in grado di aggiornarli nello stato in seguito:

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
Possiamo usare direttamente initState per fare qualcosa come foo = widget.foo, non è richiesto alcun passaggio al costruttore
Aqib

Come passare argomento a questo?
Steev James

@SteevJames il widget MyStatefulha un parametro denominato opzionale (proprietà) che puoi creare chiamandoMyStateful(foo: "my string",)
Kirill Karmazin

@Aqib initStatenon risolve un problema nel seguente scenario: ad esempio, hai creato il tuo widget Statefull con parametri vuoti e stai aspettando che i tuoi dati vengano caricati. Quando i dati vengono caricati, vuoi aggiornare il tuo widget Statefull con i nuovi dati e in questo caso quando chiami MyStatefull (newData) initState()non verrà chiamato! In questo caso didUpdateWidget(MyStatefull oldWidget)verrà chiamato e sarà necessario confrontare i dati dall'argomento oldWidget.getData()con widget.datae se non è lo stesso, chiamare setState()per ricostruire il widget.
Kirill Karmazin

1
@ kirill-karmazin puoi approfondire ulteriormente la soluzione del widget Stateless? cosa useresti invece? È una best practice del team Flutter? Grazie
camillo777

4

Per passare i valori iniziali (senza passare nulla al costruttore)

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);
  }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.