Meneruskan Data ke Widget Stateful


114

Saya bertanya-tanya apa cara yang disarankan untuk meneruskan data ke widget stateful, saat membuatnya, adalah.

Dua gaya yang pernah saya lihat adalah:

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

Metode ini menyimpan nilai dalam ServerInfodan _ServerInfoState, yang tampaknya sedikit boros.

Metode lainnya adalah dengan menggunakan 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;
    }
}

Ini tampaknya agak mundur karena status tidak lagi disimpan di _ServerInfoSatemelainkan di widget.

Apakah ada praktik terbaik untuk ini?


3
Konstruktor dapat dikurangi menjadiServerInfo(this._server);
Günter Zöchbauer

Pertanyaan ini telah ditanyakan sebelumnya: stackoverflow.com/questions/50428708/…
Blasanka


Jawaban ini ditambahkan satu bulan sebelum yang ini: stackoverflow.com/questions/50428708/…
Blasanka

Jawaban:


232

Jangan berikan parameter untuk Statemenggunakan konstruktornya. Anda hanya boleh mengakses ini menggunakan this.widget.myField.

Tidak hanya mengedit konstruktor membutuhkan banyak pekerjaan manual; itu tidak membawa apapun. Tidak ada alasan untuk menduplikasi semua bidang Widget.

EDIT:

Berikut contohnya:

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
Komentar lebih lanjut, apa pun yang Anda berikan ke objek Status melalui konstruktor tidak akan pernah diperbarui!
Jonah Williams

4
Dan di sinilah saya dan tidak mengerti komentarnya. "Jangan berikan parameter ke Status menggunakan konstruktornya". Jadi bagaimana cara mengirimkan parameter ke Negara?
KhoPhi

6
@Rexford Statesudah sebagai akses ke semua properti Statefuldengan menggunakan widgetbidang.
Rémi Rousselet

4
@ RémiRousselet Bagaimana jika saya ingin menggunakan foo untuk mengisi awal bidang teks, dan masih mengizinkan pengguna untuk mengeditnya. Haruskah saya juga menambahkan properti foo lain di negara bagian ini?
Kata Saifi

1
@ user6638204 Anda dapat membuat properti foo lain di status, dan menimpa void initState()status untuk menyetel nilai awal. Periksa opsi utas C ini sebagai contoh.
Joseph Cheng

31

Cara terbaik adalah tidak mengirimkan parameter ke kelas State menggunakan konstruktornya. Anda dapat dengan mudah mengakses di kelas Negara menggunakan widget.myField.

Sebagai contoh

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

Kirimkan data Anda saat Anda Menavigasi layar:

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

8

Jawaban lain, berdasarkan jawaban @ RémiRousselet dan untuk pertanyaan @ user6638204, jika Anda ingin meneruskan nilai awal dan masih dapat memperbaruinya di status nanti:

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
Kita bisa langsung menggunakan initState untuk melakukan sesuatu seperti foo = widget.foo, tidak perlu meneruskan ke konstruktor
Aqib

Bagaimana memberikan argumen untuk ini?
Steev James

@SteevJames widget MyStatefulmemiliki satu parameter bernama opsional (properti) Anda dapat membuat widget ini dengan meneleponMyStateful(foo: "my string",)
Kirill Karmazin

@Aqib the initStatetidak menyelesaikan masalah dalam skenario berikut: misalnya, Anda membuat widget Statefull Anda dengan parameter kosong dan Anda menunggu data Anda dimuat. Ketika data dimuat, Anda ingin memperbarui widget Statefull Anda dengan data baru dan dalam hal ini ketika Anda memanggil MyStatefull (newData), widget itu initState()tidak akan dipanggil! Dalam hal ini didUpdateWidget(MyStatefull oldWidget)akan dipanggil dan Anda perlu membandingkan data Anda dari argumen oldWidget.getData()dengan widget.datadan jika tidak sama - panggil setState()untuk membangun kembali widget.
Kirill Karmazin

1
@ kirill-karmazin dapatkah Anda menjelaskan lebih lanjut tentang solusi widget Stateless? apa yang akan kamu gunakan sebagai gantinya? Apakah ini praktik terbaik dari tim Flutter? Terima kasih
camillo777

4

Untuk meneruskan nilai awal (tanpa meneruskan apa pun ke konstruktor)

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);
  }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.