Truyền dữ liệu đến một widget trạng thái


113

Tôi đang tự hỏi cách được đề xuất để chuyển dữ liệu đến một widget trạng thái, trong khi tạo nó, là gì.

Hai phong cách tôi đã thấy là:

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

Phương pháp này giữ một giá trị cả trong ServerInfo_ServerInfoState, có vẻ hơi lãng phí.

Phương pháp khác là sử dụng 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;
    }
}

Điều này có vẻ hơi ngược vì trạng thái không còn được lưu trữ trong _ServerInfoSatemà thay vào đó là trong tiện ích.

Có phương pháp nào tốt nhất cho việc này không?


3
Các nhà xây dựng có thể được giảm xuốngServerInfo(this._server);
Günter Zöchbauer

Câu hỏi này đã được hỏi trước đó: stackoverflow.com/questions/50428708/…
Blasanka


Câu trả lời này được thêm một tháng trước câu trả lời này: stackoverflow.com/questions/50428708/…
Blasanka

Điều này có trả lời câu hỏi của bạn không? Chuyển dữ liệu StatefulWidget vào lớp State mà không sử dụng hàm tạo
Blasanka

Câu trả lời:


230

Không chuyển các tham số để Statesử dụng hàm tạo của nó. Bạn chỉ nên truy cập những bằng cách sử dụng this.widget.myField.

Không chỉ chỉnh sửa hàm tạo đòi hỏi nhiều thao tác thủ công; nó không mang lại gì cả. Không có lý do gì để sao chép tất cả các trường của Widget.

BIÊN TẬP :

Đây là một ví dụ:

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
Một chú thích thêm, bất cứ thứ gì bạn chuyển cho một đối tượng State thông qua hàm tạo sẽ không bao giờ được cập nhật!
Jonah Williams

4
Và tôi ở đây và không hiểu nhận xét. "Không truyền tham số cho State bằng cách sử dụng hàm tạo của nó". Vậy làm cách nào để truyền tham số cho State?
KhoPhi

6
@Rexford Stateđã có quyền truy cập vào tất cả các thuộc tính của Statefulbằng cách sử dụng widgettrường.
Rémi Rousselet

4
@ RémiRousselet Điều gì sẽ xảy ra nếu tôi muốn sử dụng foo để điền trước một trường văn bản và vẫn cho phép người dùng chỉnh sửa nó. Tôi cũng nên thêm một thuộc tính foo khác trong tiểu bang?
Saifi nói

1
@ user6638204 Bạn có thể tạo một thuộc tính foo khác trong trạng thái và ghi đè lên void initState()trạng thái để đặt giá trị ban đầu. Kiểm tra tùy chọn chủ đề này làm ví dụ.
Joseph Cheng

30

Cách tốt nhất là không chuyển các tham số cho lớp State bằng cách sử dụng hàm tạo của nó. Bạn có thể dễ dàng truy cập trong State class bằng cách sử dụng widget.myField.

Ví dụ

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

Chuyển dữ liệu của bạn khi bạn Điều hướng màn hình:

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

8

Một câu trả lời khác, dựa trên anwser của @ RémiRousselet và cho câu hỏi của @ user6638204, nếu bạn muốn chuyển các giá trị ban đầu và vẫn có thể cập nhật chúng ở trạng thái sau:

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
Chúng ta có thể trực tiếp sử dụng initState để làm một cái gì đó giống như foo = widget.foo, không đi qua để xây dựng là cần thiết
Aqib

Làm thế nào để chuyển đối số cho điều này?
Regiv James

@SteevJames widget MyStatefulđã một tùy chọn tham số có tên (bất động sản), bạn có thể tạo widget này bằng cách gọiMyStateful(foo: "my string",)
Kirill Karmazin

@Aqib initStatekhông giải quyết được sự cố trong trường hợp sau: ví dụ: bạn đã tạo tiện ích con Statefull của mình với các tham số trống và bạn đang chờ tải dữ liệu của mình. Khi dữ liệu được tải, bạn muốn cập nhật tiện ích Statefull với dữ liệu mới và trong trường hợp này khi bạn gọi MyStatefull (newData), nó initState()sẽ không được gọi! Trong trường hợp didUpdateWidget(MyStatefull oldWidget)này sẽ được gọi và bạn sẽ cần so sánh dữ liệu của mình từ đối số oldWidget.getData()với widget.datavà nếu nó không giống nhau - hãy gọi setState()để xây dựng lại tiện ích con.
Kirill Karmazin

1
@ kirill-karmazin, bạn có thể nói rõ hơn về giải pháp widget Stateless không? bạn sẽ sử dụng cái gì thay thế? Đó có phải là phương pháp hay nhất từ ​​nhóm Flutter không? Cảm ơn bạn
camillo777

4

Để truyền các giá trị ban đầu (mà không truyền bất kỳ thứ gì cho hàm tạo)

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);
  }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.