将数据传递给有状态的小部件


113

我想知道在创建数据时将数据传递给有状态的小部件的推荐方法是什么。

我见过的两种样式是:

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);
君特Zöchbauer

早些时候有人问过这个问题:stackoverflow.com/questions/50428708/…–
Blasanka,

这回答了你的问题了吗?在Flutter
中将

:这个答案是一个月新增此人之前stackoverflow.com/questions/50428708/...
Blasanka

Answers:


230

不要将参数传递给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")
    );
  }
}

23
进一步说明,通过构造函数传递给State对象的任何内容都永远不会更新!
乔纳·威廉姆斯

4
我在这里也听不懂这句话。“不要使用其构造函数将参数传递给State”。那么如何将参数传递给State?
KhoPhi

6
@Rexford State已经可以Stateful通过使用该widget字段来访问的所有属性。
雷米Rousselet

4
@RémiRousselet如果我想使用foo来预填充文本字段,并且仍然允许用户对其进行编辑,该怎么办。我还应该在状态中添加另一个foo属性吗?
赛义夫赛义德

1
@ user6638204您可以在state中创建另一个foo属性,并覆盖void initState()state以设置初始值。以该线程 选项C为例。
Joseph Cheng)

30

最好的方法是不要使用其构造函数将参数传递给State类。您可以使用在State类中轻松访问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)));

8

如果您要传递初始值并且以后仍然能够在状态中更新它们,则以@RémiRousselet的anwser为基础,并针对@ 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);
  }
}

7
我们可以直接使用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 '19

4

用于传递初始值(不向构造函数传递任何内容)

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);
  }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.