การส่งผ่านข้อมูลไปยังวิดเจ็ตสถานะ


120

ฉันสงสัยว่าวิธีที่แนะนำในการส่งผ่านข้อมูลไปยังวิดเจ็ตที่มีสถานะเป็นอย่างไรในขณะที่สร้างมันคืออะไร

สองสไตล์ที่ฉันเคยเห็นคือ:

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

วิธีนี้จะเก็บค่าทั้งในServerInfoและ_ServerInfoStateซึ่งดูเหมือนจะสิ้นเปลืองไปหน่อย

วิธีอื่นคือการใช้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;
    }
}

ดูเหมือนว่าจะย้อนกลับไปเล็กน้อยเนื่องจากสถานะไม่ได้ถูกเก็บไว้อีกต่อไป_ServerInfoSateแต่จะอยู่ในวิดเจ็ตแทน

มีแนวทางปฏิบัติที่ดีที่สุดสำหรับสิ่งนี้หรือไม่?


3
ตัวสร้างสามารถลดลงเป็นServerInfo(this._server);
GünterZöchbauer

มีการถามคำถามนี้ก่อนหน้านี้: stackoverflow.com/questions/50428708/…
Blasanka


คำตอบนี้เพิ่มมาหนึ่งเดือนก่อนคำตอบนี้: stackoverflow.com/questions/50428708/…
Blasanka

คำตอบ:


244

อย่าส่งผ่านพารามิเตอร์ไปStateใช้ตัวสร้าง คุณควรเข้าถึงสิ่งเหล่านี้โดยใช้this.widget.myFieldไฟล์.

ไม่เพียง แต่การแก้ไขคอนสตรัคเตอร์เท่านั้นที่ต้องใช้งานด้วยตนเองจำนวนมาก มันไม่ได้นำอะไรมา ไม่มีเหตุผลที่จะทำซ้ำฟิลด์ทั้งหมดของWidget.

แก้ไข:

นี่คือตัวอย่าง:

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

24
ความคิดเห็นเพิ่มเติมสิ่งที่คุณส่งผ่านไปยังวัตถุสถานะผ่านตัวสร้างจะไม่ได้รับการอัปเดต!
Jonah Williams

4
และที่นี่ฉันและไม่เข้าใจความคิดเห็น "ไม่ต้องส่งพารามิเตอร์ไปยังสถานะโดยใช้ตัวสร้าง" แล้วฉันจะส่งพารามิเตอร์ไปยัง State ได้อย่างไร?
KhoPhi

6
@Rexford Stateอยู่แล้วในการเข้าถึงคุณสมบัติทั้งหมดของStatefulโดยใช้widgetฟิลด์
Rémi Rousselet

4
@ RémiRousseletจะเป็นอย่างไรหากฉันต้องการใช้ foo เพื่อเติมฟิลด์ข้อความล่วงหน้าและยังอนุญาตให้ผู้ใช้แก้ไขได้ ฉันควรเพิ่มคุณสมบัติ foo อื่นในรัฐด้วยหรือไม่?
กล่าวว่า Saifi

1
@ user6638204 คุณสามารถสร้างคุณสมบัติ foo อื่นในสถานะและแทนที่void initState()สถานะเพื่อตั้งค่าเริ่มต้น ตรวจสอบเธรดนี้ ตัวเลือก C เป็นตัวอย่าง
Joseph Cheng

31

วิธีที่ดีที่สุดคืออย่าส่งผ่านพารามิเตอร์ไปยัง State class โดยใช้ตัวสร้าง widget.myFieldคุณสามารถเข้าถึงได้อย่างง่ายดายในระดับรัฐใช้

ตัวอย่างเช่น

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

ส่งผ่านข้อมูลของคุณเมื่อคุณนำทางหน้าจอ:

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

9

คำตอบอื่นสร้างจาก anwser ของ @ RémiRousseletและสำหรับคำถามของ @ user6638204 หากคุณต้องการส่งผ่านค่าเริ่มต้นและยังสามารถอัปเดตได้ในสถานะในภายหลัง:

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

8
เราสามารถใช้ initState เพื่อทำบางสิ่งเช่น foo = widget.foo ได้โดยตรงไม่จำเป็นต้องส่งผ่านไปยังตัวสร้าง
Aqib

จะส่งผ่านข้อโต้แย้งนี้ได้อย่างไร?
Steev James

@SteevJames วิดเจ็ตMyStatefulมีพารามิเตอร์ที่มีชื่อเป็นทางเลือก (คุณสมบัติ) ที่คุณสามารถสร้างวิดเจ็ตนี้ได้โดยการโทรMyStateful(foo: "my string",)
Kirill Karmazin

@Aqib initStateไม่ได้แก้ปัญหาในสถานการณ์ต่อไปนี้: ตัวอย่างเช่นคุณสร้างวิดเจ็ต Statefull ด้วยพารามิเตอร์ว่างเปล่าและคุณกำลังรอให้ข้อมูลของคุณโหลด เมื่อข้อมูลถูกโหลดคุณต้องการอัปเดตวิดเจ็ต Statefull ของคุณด้วยข้อมูลใหม่และในกรณีนี้เมื่อคุณเรียก MyStatefull (newData) initState()จะไม่ถูกเรียก! ในกรณีนี้didUpdateWidget(MyStatefull oldWidget)จะถูกเรียกว่าและคุณจะต้องเปรียบเทียบข้อมูลของคุณจากการโต้แย้งoldWidget.getData()ด้วยwidget.dataและถ้ามันไม่เหมือนกัน - โทรsetState()ในการสร้างเครื่องมือที่
Kirill Karmazin

1
@ kirill-karmazin คุณสามารถอธิบายเพิ่มเติมเกี่ยวกับโซลูชันวิดเจ็ตไร้สถานะได้หรือไม่? คุณจะใช้อะไรแทน? เป็นแนวทางปฏิบัติที่ดีที่สุดจากทีม Flutter หรือไม่? ขอบคุณ
camillo777

5

สำหรับการส่งผ่านค่าเริ่มต้น (โดยไม่ส่งผ่านอะไรไปยังตัวสร้าง)

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);
  }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.