Pasar datos a un widget con estado


113

Me pregunto cuál es la forma recomendada de pasar datos a un widget con estado, mientras se crea.

Los dos estilos que he visto son:

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

Este método mantiene un valor en ServerInfoy _ServerInfoState, lo que parece un poco derrochador.

El otro método es utilizar 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;
    }
}

Esto parece un poco al revés, ya que el estado ya no se almacena _ServerInfoSateen el widget, sino que lo hace.

¿Existe una buena práctica para esto?


3
El constructor se puede reducir aServerInfo(this._server);
Günter Zöchbauer

Esta pregunta se ha realizado anteriormente: stackoverflow.com/questions/50428708/…
Blasanka


Esta respuesta se agrega un mes antes de esta: stackoverflow.com/questions/50428708/…
Blasanka

Respuestas:


230

No pase parámetros para Stateusar su constructor. Solo debe acceder a estos utilizando this.widget.myField.

No solo editar el constructor requiere mucho trabajo manual; no trae nada. No hay razón para duplicar todos los campos de Widget.

EDITAR:

He aquí un ejemplo:

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
Un comentario adicional, ¡cualquier cosa que pase a un objeto State a través del constructor nunca se actualizará!
Jonah Williams

4
Y aquí estoy y no entiendo el comentario. "No pase parámetros al estado usando su constructor". Entonces, ¿cómo paso los parámetros al estado?
KhoPhi

6
@Rexford Stateya tiene acceso a todas las propiedades de Statefulmediante el uso del widgetcampo.
Rémi Rousselet

4
@ RémiRousselet ¿Qué sucede si quiero usar foo para rellenar previamente un campo de texto y aún permitir que el usuario lo edite? ¿Debo agregar también otra propiedad foo en el estado?
Dijo Saifi

1
@ user6638204 Puede crear otra propiedad foo en el estado y anular void initState()el estado para establecer el valor inicial. Marque esta opción de hilo C como ejemplo.
Joseph Cheng

30

La mejor manera es no pasar parámetros a la clase State usando su constructor. Puede acceder fácilmente en la clase estatal utilizando widget.myField.

Por ejemplo

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

Pasa tus datos cuando navegas por la pantalla:

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

8

Otra respuesta, basada en la respuesta de @ RémiRousselet y para la pregunta de @ user6638204, si desea pasar valores iniciales y aún poder actualizarlos en el estado más tarde:

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
Podemos usar initState directamente para hacer algo como foo = widget.foo, no se requiere pasar al constructor
Aqib

¿Cómo pasar el argumento a esto?
Steev James

@SteevJames el widget MyStatefultiene un parámetro llamado opcional (propiedad) que puede crear este widget llamandoMyStateful(foo: "my string",)
Kirill Karmazin

@Aqib the initStateno resuelve un problema en el siguiente escenario: por ejemplo, creó su widget Statefull con parámetros vacíos y está esperando que se carguen sus datos. Cuando se cargan los datos, desea actualizar su widget Statefull con los datos nuevos y, en este caso, cuando llame a MyStatefull (newData), ¡ initState()no se llamará! En este caso didUpdateWidget(MyStatefull oldWidget), se llamará y necesitará comparar sus datos del argumento oldWidget.getData()con widget.datay si no es el mismo, llamar setState()para reconstruir el widget.
Kirill Karmazin

1
@ kirill-karmazin ¿puedes dar más detalles sobre la solución del widget sin estado? ¿Qué usarías en su lugar? ¿Es una de las mejores prácticas del equipo de Flutter? Gracias
camillo777

4

Para pasar valores iniciales (sin pasar nada al constructor)

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);
  }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.