Przekazywanie danych do Stateful Widget

115

Zastanawiam się, jaki jest zalecany sposób przekazywania danych do widgetu stanowego podczas jego tworzenia.

Dwa style, które widziałem to:

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

Ta metoda zachowuje wartość zarówno w, jak ServerInfoi _ServerInfoState, co wydaje się nieco marnotrawne.

Inną metodą jest użycie 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;
    }
}

Wydaje się to trochę wstecz, ponieważ stan nie jest już przechowywany w _ServerInfoSatewidgecie.

Czy istnieje najlepsza praktyka?

Mojachiee
źródło
3
Konstruktora można zredukować doServerInfo(this._server);
Günter Zöchbauer
To pytanie zostało zadane wcześniej: stackoverflow.com/questions/50428708/…
Blasanka
Ta odpowiedź została dodana miesiąc przed tą: stackoverflow.com/questions/50428708/…
Blasanka
Czy to odpowiada na twoje pytanie? Przekaż dane StatefulWidget do klasy State bez użycia konstruktora
Blasanka

Odpowiedzi:

233

Nie przekazuj parametrów do Statejego konstruktora. Powinieneś uzyskać do nich dostęp tylko za pomocą this.widget.myField.

Nie tylko edycja konstruktora wymaga dużo pracy ręcznej; to nic nie przynosi. Nie ma powodu, aby powielać wszystkie pola Widget.

EDYTOWAĆ :

Oto przykład:

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")
    );
  }
}
Rémi Rousselet
źródło
23
Kolejny komentarz: wszystko, co przekazujesz do obiektu State za pośrednictwem konstruktora, nigdy nie zostanie zaktualizowane!
Jonah Williams
4
I oto jestem i nie rozumiem komentarza. „Nie przekazuj parametrów do State używając jego konstruktora”. Jak więc przekazać parametry do stanu?
KhoPhi,
6
@Rexford Statejuż jako dostęp do wszystkich właściwości Statefulza pomocą widgetpola.
Rémi Rousselet
4
@ RémiRousselet A co, jeśli chcę użyć foo do wstępnego wypełnienia pola tekstowego i nadal pozwalać użytkownikowi na jego edycję. Czy powinienem również dodać kolejną właściwość foo w stanie?
Powiedział Saifi
1
@ user6638204 Możesz utworzyć kolejną właściwość foo w stanie i nadpisać void initState()stan w celu ustawienia wartości początkowej. Zaznacz opcję C wątku jako przykład.
Joseph Cheng,
31

Najlepszym sposobem jest nie przekazywanie parametrów do klasy State przy użyciu jej konstruktora. Możesz łatwo uzyskać dostęp w klasie State za pomocą widget.myField.

Na przykład

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

Przekaż swoje dane podczas nawigacji na ekranie:

 Navigator.of(context).push(MaterialPageRoute(builder: (context) => UserData("WonderClientName",132)));
Sanjayrajsinh
źródło
8

Kolejna odpowiedź, opierając się na anwser @ RémiRousselet i dla pytania @ user6638204, jeśli chcesz przekazać wartości początkowe i nadal mieć możliwość ich późniejszej aktualizacji w stanie:

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);
  }
}
Nicolas Dion-Bouchard
źródło
7
Możemy bezpośrednio użyć initState do zrobienia czegoś takiego jak foo = widget.foo, nie jest wymagane przekazywanie do konstruktora
Aqib
Jak przekazać do tego argument?
Steev James
@SteevJames widżet MyStatefulma jeden opcjonalny nazwany parametr (właściwość), który możesz utworzyć, dzwoniącMyStateful(foo: "my string",)
Kirill Karmazin
@Aqib the initStatenie rozwiązuje problemu w następującym scenariuszu: na przykład utworzyłeś widget Statefull z pustymi parametrami i czekasz na załadowanie danych. Po załadowaniu danych chcesz zaktualizować widget Statefull o świeże dane, aw tym przypadku, gdy wywołasz MyStatefull (newData), initState()nie zostanie on wywołany! W takim przypadku didUpdateWidget(MyStatefull oldWidget)zostanie wywołany i będziesz musiał porównać dane z argumentu oldWidget.getData()z, widget.dataa jeśli nie jest to to samo - wywołaj, setState()aby odbudować widget.
Kirill Karmazin
1
@ kirill-karmazin Czy możesz szerzej omówić rozwiązanie dotyczące widżetu bezstanowego? czego użyłbyś zamiast tego? Czy to najlepsza praktyka zespołu Flutter? Dziękuję
camillo777
4

Do przekazywania wartości początkowych (bez przekazywania niczego do konstruktora)

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);
  }
}
Daksh Shah
źródło