209

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

我见过的两种风格是:

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,而是在小部件中。

对此有最佳做法吗?

4

6 回答 6

409

不要将参数传递给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")
    );
  }
}
于 2018-06-12T13:48:56.427 回答
53

最好的方法是不要使用它的构造函数将参数传递给 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)));
于 2019-11-11T08:29:52.787 回答
16

另一个答案,建立在@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);
  }
}
于 2019-05-29T15:12:58.627 回答
9

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

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);
  }
}
于 2019-10-09T20:43:02.897 回答
2

Flutter 的 stateful widgets API 有点尴尬:将数据存储在 Widget 中以便build()在对象中的方法中访问它State如果您不想使用一些更大的状态管理选项(Provider、BLoC),请使用 flutter_hooks(https:// pub.dev/packages/flutter_hooks ) - 它是 s 的更好更干净的替代品SatefullWidget

class Counter extends HookWidget {
  final int _initialCount;

  Counter(this._initialCount = 0);
  
  @override
  Widget build(BuildContext context) {
    final counter = useState(_initialCount);

    return GestureDetector(
      // automatically triggers a rebuild of Counter widget
      onTap: () => counter.value++,
      child: Text(counter.value.toString()),
    );
  }
}
于 2021-03-02T20:15:53.533 回答
1

@Rémi Rousselet、@Sanjayrajsinh、@Daksh Shah 也更好。但我也定义了这是从起点开始的。哪个参数是哪个值

   import 'package:flutter/material.dart';
    
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      String name = "Flutter Demo";
      String description = "This is Demo Application";
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: MainActivity(
            appName: name,
            appDescription: description,
          ),
        );
      }
    }
    
    class MainActivity extends StatefulWidget {
      MainActivity({Key key, this.appName, this.appDescription}) : super(key: key);
      var appName;
      var appDescription;
    
      @override
      _MainActivityState createState() => _MainActivityState();
    }
    
    class _MainActivityState extends State<MainActivity> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.appName),
          ),
          body: Scaffold(
            body: Center(
              child: Text(widget.appDescription),
            ),
          ),
        );
      }
    }
于 2020-10-08T13:16:44.030 回答