Qual è la relazione tra widget con stato e senza stato in Flutter?


105

Un widget con stato è definito come qualsiasi widget che cambia il proprio stato durante la sua durata. Ma è una pratica molto comune per un StatelessWidgetavere StatefulWidgetuno dei suoi figli. Non StatelessWidgetdiventa stateful se ha StatefulWidgetcome uno dei suoi figli?

Ho provato a esaminare la documentazione come parte del codice di StatelessWidget, ma non sono riuscito a capire come una StatelessWidgetlattina possa avere Statefulwidgetcome figli e rimanere ancora StatelessWidget.

Qual è la relazione e la differenza tra widget con stato e senza stato in Flutter?


2
Puoi comporre il tuo layout da diversi tipi di widget, tuttavia ciò non significa che stai ereditando le caratteristiche della composizione per influenzare ogni widget. Quello che voglio dire è che puoi avere un contenitore che è senza stato che ha un figlio di un altro contenitore che è dichiarato come StatefulWidget da qualche altra parte, lo stato del contenitore influenzerà solo questo componente solo. Quindi, si tratta di avere una composizione da diversi tipi di widget, ogni funzione che ti serve.
aziza

1
Per complicare le cose ancora più, c'è un terzo tipo di widget: InheritedWidget; Che può fare l' StatelessWidgetaggiornamento.
Rémi Rousselet

Risposte:


103

Uno StatelessWidget non si ricostruirà mai da solo (ma può farlo da eventi esterni). Uno StatefulWidget può. Questa è la regola d'oro.

MA qualsiasi tipo di widget può essere ridipinto in qualsiasi momento.

Stateless significa solo che tutte le sue proprietà sono immutabili e che l'unico modo per modificarle è creare una nuova istanza di quel widget. Ad esempio, non blocca l'albero dei widget.

Ma non dovresti preoccuparti di qual è il tipo di tuoi figli. Non ha alcun impatto su di te.


11
(Relativamente nuovo per il framework). Qual è la differenza tra rebuilderepaint
user462455

Anche dai commenti nel codice del framework flutter, apparentemente anche StateFulWidgeti messaggi sono immutabili.
user462455

3
La compilazione di un widget è fondamentalmente una chiamata al metodo "build", seguita dalla creazione / aggiornamento della corrispondente renderbox; che è seguito dal processo di pittura. Che stamperà questi renderbox sullo schermo.
Rémi Rousselet,

le classi che ereditano "StatefulWidget" non sono modificabili. Ma lo stato (State <YourWidget>) stesso è mutevole.
Rémi Rousselet,

1
@ RémiRousselet I widget stateful e stateless ricostruiscono entrambi ogni frame, secondo flutter.dev/docs/get-started/flutter-for/…
Matt

82

StatefulWidget vs StatelessWidget.

inserisci qui la descrizione dell'immagine

StatelessWidget - Un widget che non richiede uno stato modificabile.

  • Un widget senza stato è un widget che descrive parte dell'interfaccia utente costruendo una costellazione di altri widget che descrivono l'interfaccia utente in modo più concreto. Il processo di costruzione continua in modo ricorsivo fino a quando la descrizione dell'interfaccia utente non è completamente concreta (ad esempio, consiste interamente di RenderObjectWidgets, che descrivono RenderObjects concreti).

  • Il statelesswidget è utile quando la parte dell'interfaccia utente che si sta descrivendo non dipende da nient'altro che dalle informazioni di configurazione nell'oggetto stesso e dal BuildContext in cui il widget è gonfiato. Per le composizioni che possono cambiare dinamicamente, ad esempio a causa di uno stato guidato dal clock interno o in base a uno stato del sistema, considerare l'utilizzo StatefulWidget.

class GreenFrog extends StatelessWidget {
  const GreenFrog({ Key key }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(color: const Color(0xFF2DBD3A));
  }
}

StatefulWidget - Un widget con stato mutabile.

  • I widget con stato sono utili quando la parte dell'interfaccia utente che stai descrivendo può cambiare dinamicamente.

Quando Flutter costruisce a StatefulWidget, crea un oggetto State. Questo oggetto è dove si tiene tutto lo stato mutevole per quel widget.

Il concetto di stato è definito da due cose:

1) I dati utilizzati dal widget potrebbero cambiare.

2) I dati non possono essere letti in modo sincrono quando il widget viene creato. (Tutto lo stato deve essere stabilito prima che venga chiamato il metodo build).

StatefulWidget lifecycle

Il ciclo di vita prevede i seguenti passaggi semplificati:

  1. createState () - Quando Flutter viene istruito a costruire uno StatefulWidget, chiama immediatamente createState().
  • Crea lo stato modificabile per questo widget in una determinata posizione nell'albero.

  • Le sottoclassi dovrebbero sovrascrivere questo metodo per restituire un'istanza appena creata della loro sottoclasse di stato associata:

@override
_MyState createState() => _MyState();
  1. montato == true - Tutti i widget hanno una this.mountedproprietà bool . Diventa vero quando buildContextviene assegnato. È un errore chiamare setStatequando un widget è smontato. Se questo oggetto State è attualmente in un albero.
  • Dopo aver creato un oggetto State e prima di chiamare initState, il framework "monta" l'oggetto State associandolo a un file
    BuildContext. L'oggetto State rimane montato fino alla
    chiamata del framework dispose(), dopodiché il framework non chiederà mai più
    all'oggetto State di essere compilato.

  • È un errore chiamare setState a meno che mount non sia vero.

bool get mounted => _element != null;
  1. initState () - Questo è il primo metodo chiamato quando il widget viene creato (dopo il costruttore della classe, ovviamente).

initStateviene chiamato una sola volta. Deve chiamaresuper.initState().

  • Inizializza i dati che si basano sul BuildContext specifico per l'istanza creata del widget.

  • Inizializza le proprietà che si basano sul "genitore" di questi widget nell'albero.

  • Iscriviti a Streams ChangeNotifierso qualsiasi altro oggetto che potrebbe modificare i dati su questo widget.

@override
initState() {
  super.initState();
  // Add listeners to this class
  cartItemStream.listen((data) {
    _updateWidget(data);
  });
}
  1. didChangeDependencies () - Chiamato quando una dipendenza di questo oggetto State cambia.
  • Questo metodo viene chiamato anche immediatamente dopo initState. È sicuro chiamare BuildContext.inheritFromWidgetOfExactTypeda questo metodo.

  • Le sottoclassi raramente sovrascrivono questo metodo perché il framework chiama sempre build dopo le modifiche alle dipendenze. Alcune sottoclassi sovrascrivono questo metodo perché devono svolgere un lavoro costoso (ad esempio, i recuperi di rete) quando le loro dipendenze cambiano e quel lavoro sarebbe troppo costoso da fare per ogni build.

@protected
@mustCallSuper
void didChangeDependencies() { }
  1. build () - Descrive la parte dell'interfaccia utente rappresentata dal widget.

Il framework chiama questo metodo in una serie di situazioni diverse:

  • Dopo aver chiamato initState.
  • Dopo aver chiamato didUpdateWidget.
  • Dopo aver ricevuto una chiamata a setState.
  • Dopo che una dipendenza di questo oggetto State cambia (ad esempio, un InheritedWidget referenziato dalle modifiche di build precedenti).
  • Dopo aver chiamato disattivare e quindi reinserire l'oggetto State nella struttura ad albero in un'altra posizione.
  • Il framework sostituisce il sottoalbero sotto questo widget con il widget restituito da questo metodo, aggiornando il sottoalbero esistente o rimuovendo il sottoalbero e gonfiando un nuovo sottoalbero, a seconda che il widget restituito da questo metodo possa aggiornare la radice del sottoalbero esistente , come determinato chiamando Widget.canUpdate.

  • In genere le implementazioni restituiscono una costellazione di widget appena creata che sono configurati con le informazioni dal costruttore di questo widget, il BuildContext specificato e lo stato interno di questo oggetto State.

@override
  Widget build(BuildContext context, MyButtonState state) {
    ... () { print("color: $color"); } ...
  }
  1. didUpdateWidget () - Chiamato ogni volta che la configurazione del widget cambia.
  • Se il widget genitore si ricostruisce e richiede che questa posizione nell'albero si aggiorni per visualizzare un nuovo widget con lo stesso tipo di runtime e Widget.key, il framework aggiornerà la proprietà del widget di questo oggetto State per fare riferimento al nuovo widget e quindi lo chiamerà metodo con il widget precedente come argomento.

  • Sostituisci questo metodo per rispondere quando il widget cambia (ad esempio, per avviare animazioni implicite).

  • Il framework chiama sempre build dopo aver chiamato didUpdateWidget, il che significa che qualsiasi chiamata a setState in didUpdateWidget è ridondante.

@mustCallSuper
@protected
void didUpdateWidget(covariant T oldWidget) { }
  1. setState () - Ogni volta che modifichi lo stato interno di un oggetto State, apporta la modifica in una funzione a cui passi setState:
  • La chiamata a setState notifica al framework che lo stato interno di questo oggetto è cambiato in un modo che potrebbe influire sull'interfaccia utente in questa sottostruttura, che fa sì che il framework pianifichi una compilazione per
    questo oggetto State.

  • Se si modifica direttamente lo stato senza chiamare setState , il framework potrebbe non pianificare una compilazione e l'interfaccia utente per questa sottostruttura potrebbe non essere aggiornata per riflettere il nuovo stato.

setState(() { _myState = newValue });
  1. disable () - Deactivate viene chiamato quando State viene rimosso dall'albero, ma potrebbe essere reinserito prima che il cambio di frame corrente sia terminato. Questo metodo esiste fondamentalmente perché gli oggetti State possono essere spostati da un punto all'altro di un albero.
  • Il framework chiama questo metodo ogni volta che rimuove questo oggetto State dall'albero. In alcuni casi, il framework reinserirà l'oggetto State in un'altra parte dell'albero (ad esempio, se la sottostruttura contenente questo oggetto State è innestata da una posizione a un'altra dell'albero). Se ciò accade, il framework si assicurerà di chiamare build per dare all'oggetto State la possibilità di adattarsi alla sua nuova posizione nell'albero. Se il framework reinserisce questa sottostruttura, lo farà prima della fine del fotogramma dell'animazione in cui la sottostruttura è stata rimossa dall'albero. Per questo motivo, gli oggetti State possono posticipare il rilascio della maggior parte delle risorse finché il framework non chiama il metodo dispose.

Questo è usato raramente.

@protected
@mustCallSuper
void deactivate() { }
  1. dispose () - Chiamato quando questo oggetto viene rimosso dall'albero in modo permanente.
  • Il framework chiama questo metodo quando questo oggetto State non verrà mai più compilato. Dopo le chiamate al framework dispose(), l'oggetto State viene considerato non montato e la proprietà mounted è false. È un errore chiamare setState a questo punto. Questa fase del ciclo di vita è terminale: non c'è modo di rimontare un oggetto State che è stato eliminato.

  • Le sottoclassi dovrebbero sovrascrivere questo metodo per rilasciare qualsiasi risorsa trattenuta da questo oggetto (ad esempio, interrompere qualsiasi animazione attiva).

@protected
@mustCallSuper
void dispose() {
  assert(_debugLifecycleState == _StateLifecycle.ready);
  assert(() { _debugLifecycleState = _StateLifecycle.defunct; return true; }());
}

inserisci qui la descrizione dell'immagine

Per maggiori informazioni vai qui qui , qui


26

Dalla documentazione su flutter.io :

... La cosa importante da notare qui è che entrambi i widget Stateless e Stateful si comportano allo stesso modo. Ricostruiscono ogni frame, la differenza è che StatefulWidget ha un oggetto State che memorizza i dati di stato attraverso i frame e li ripristina.

Se sei in dubbio, ricorda sempre questa regola: se un widget cambia (l'utente interagisce con esso, ad esempio) è stateful. Tuttavia, se un bambino sta reagendo al cambiamento, il genitore contenitore può ancora essere un widget Stateless se il genitore non reagisce al cambiamento.


14

Come menzionato nei documenti di flutter

Qual e il punto?

Alcuni widget sono con stato e altri sono senza stato. Se un widget cambia, ad esempio l'utente interagisce con esso, è stateful. Lo stato di un widget è costituito da valori che possono cambiare, come il valore corrente di un cursore o se una casella di controllo è selezionata. Lo stato di un widget viene memorizzato in un oggetto State, separando lo stato del widget dal suo aspetto. Quando lo stato del widget cambia, l'oggetto state chiama setState (), dicendo al framework di ridisegnare il widget.

Un widget senza stato non ha uno stato interno da gestire. Icon, IconButton e Text sono esempi di widget senza stato, che sottoclasse StatelessWidget.

Un widget con stato è dinamico. L'utente può interagire con un widget con stato (digitando in un modulo o spostando un dispositivo di scorrimento, ad esempio) o questo cambia nel tempo (forse un feed di dati causa l'aggiornamento dell'interfaccia utente). Checkbox, Radio, Slider, InkWell, Form e TextField sono esempi di widget con stato, che sottoclasse StatefulWidget.

https://flutter.io/tutorials/interactive/#stateful-stateless


10

Lo stato è un'informazione che (1) può essere letta in modo sincrono quando il widget viene creato e (2) potrebbe cambiare durante la durata del widget. È responsabilità dell'implementatore del widget garantire che lo Stato venga prontamente informato quando tale stato cambia, utilizzando State.setState.

StatefulWidget :

Un widget con stato è un widget che descrive parte dell'interfaccia utente costruendo una costellazione di altri widget che descrivono l'interfaccia utente in modo più concreto. Il processo di costruzione continua in modo ricorsivo fino a quando la descrizione dell'interfaccia utente non è completamente concreta (ad esempio, consiste interamente di RenderObjectWidgets, che descrivono RenderObjects concreti).

I widget con stato sono utili quando la parte dell'interfaccia utente che si sta descrivendo può cambiare dinamicamente, ad esempio a causa di uno stato guidato dall'orologio interno o in base a uno stato del sistema. Per le composizioni che dipendono solo dalle informazioni di configurazione nell'oggetto stesso e nel BuildContext in cui il widget è gonfiato, considera l'utilizzo di StatelessWidget.

Le istanze StatefulWidget stesse sono immutabili e memorizzano il loro stato mutabile in oggetti State separati che vengono creati dal metodo createState, o in oggetti a cui tale Stato si iscrive, ad esempio oggetti Stream o ChangeNotifier, a cui i riferimenti sono memorizzati nei campi finali su StatefulWidget si.

StatelessWidget :

Un widget senza stato è un widget che descrive parte dell'interfaccia utente costruendo una costellazione di altri widget che descrivono l'interfaccia utente in modo più concreto. Il processo di costruzione continua in modo ricorsivo fino a quando la descrizione dell'interfaccia utente non è completamente concreta (ad esempio, consiste interamente di RenderObjectWidgets, che descrivono RenderObjects concreti).

I widget stateless sono utili quando la parte dell'interfaccia utente che stai descrivendo non dipende da nient'altro che dalle informazioni di configurazione nell'oggetto stesso e dal BuildContext in cui il widget è gonfiato. Per le composizioni che possono cambiare dinamicamente, ad esempio a causa di uno stato di clock interno, o a seconda di uno stato del sistema, considerare l'utilizzo di StatefulWidget.


9

I widget stateless sono widget statici. Hai solo bisogno di passare alcune proprietà prima di inizializzare i widget stateless. Non dipendono da alcuna modifica dei dati o da qualsiasi modifica del comportamento. Per esempio. Text, Icon, RaisedButton sono widget senza stato.

I widget con stato sono widget dinamici, possono essere aggiornati durante il runtime in base all'azione dell'utente o alla modifica dei dati. Se un widget può cambiare il suo stato durante il runtime, sarà widget con stato.

Modifica 15/11/2018

I widget stateless possono eseguire nuovamente il rendering se i dati di input / esterni sono cambiati (i dati esterni sono dati passati attraverso il costruttore). Poiché i widget stateless non hanno uno stato, verrà eseguito il rendering una volta e non si aggiorneranno, ma verranno aggiornati solo quando i dati esterni cambiano.

Mentre Stateful Widgets con stato hanno uno stato interno e possono eseguire nuovamente il rendering se i dati di input cambiano o se lo stato del widget cambia.

Entrambi i widget senza stato e con stato hanno un ciclo di vita diverso.


Anche dopo aver passato un nuovo dato dall'esterno al Statelesswidget, possiamo cambiarlo anche in tempo di esecuzione ma non si chiama Statefulwidget (a differenza della tua ultima riga).
CopsOnRoad

Puoi spiegare come un widget Stateless può "essere aggiornato quando cambiano dati esterni"? (Con "dati esterni che sono dati passati attraverso il costruttore".) Il costruttore non verrà chiamato solo una volta? Come cambiano i dati passati attraverso il costruttore?
user1596274

8

Mi viene in mente un'analogia molto semplice. Hai qualche mobile con libri, decorazioni e una TV. L'arredamento è apolide, non fa niente non si muove. Nella TV, dall'altra parte, è possibile accenderla, spegnerla, cambiare canale, riprodurre un film se è collegato un DVD, ecc. La TV ha uno stato interno che influisce sul modo in cui si comporta. Nell'arredamento non hai stato. La presenza della TV nei mobili non aggiunge uno stato ad essa. Spero che sia di aiuto.


Questo non risponde alla domanda specifica del richiedente.
Isaia

1
Questa è una grande analogia!
William Terrill

6

Rispondi alla domanda Stack Overflow: statefulness vs apolidia .

In Flutter, la differenza è che i widget senza stato possono essere definiti solo da tutti gli argomenti del costruttore. Se crei due widget senza stato utilizzando gli stessi argomenti, saranno gli stessi.

Un widget con stato, tuttavia, non è necessariamente lo stesso di un altro creato con gli stessi argomenti del costruttore. Potrebbe essere in uno stato diverso.
In realtà, un widget con stato è immutabile (senza stato) di per sé, ma Flutter gestisce un oggetto di stato separato e lo associa al widget, come spiegato nel documento StatefulWidget . Ciò significa che quando Flutter ricostruisce un widget con stato, verificherà se deve riutilizzare un oggetto di stato precedente e, se lo si desidera, collegherà quell'oggetto di stato al widget.

Il widget genitore è senza stato perché non si preoccupa dello stato del suo figlio. Il bambino con stato stesso (o tecnicamente Flutter) si prenderà cura del proprio stato.
Ad un livello elevato, concordo sul fatto che questo renda il widget genitore con stato, perché due genitori potrebbero contenere due figli con stati diversi e quindi essere tecnicamente diversi. Ma dal punto di vista di Flutter, costruisce il widget genitore senza preoccuparsi dello stato e solo durante la costruzione il bambino considererà il suo stato.


5

Cosa sono i widget con stato e senza stato?

TL; DR: un widget che consente di aggiornare lo schermo è un widget con stato. Un widget che non lo è è Stateless.

Più in dettaglio, un widget dinamico con contenuto che può cambiare dovrebbe essere un widget Stateful. Un widget Stateless può modificare il contenuto solo quando i parametri vengono modificati e quindi deve essere eseguito al di sopra del punto della sua posizione nella gerarchia del widget. Uno schermo o un widget contenente contenuto statico dovrebbe essere un widget senza stato, ma per modificare il contenuto deve essere stateful.

Ho trovato questo contenuto relativo su una storia media interessante. Prego!


4

Stateless : lo stato del widget viene creato SOLO UNA VOLTA, quindi può aggiornare i valori ma non lo stato esplicitamente. Questo è chiaro anche dalla struttura. Ecco perché ha solo una classe che si estende con StatelessWidget. Quindi, se lo dico, non potranno mai rieseguire build()nuovamente il metodo.

Stateful : i widget possono aggiornare il proprio STATO (localmente) e i valori più volte all'attivazione dell'evento . Questo è il motivo, anche l'implementazione è diversa. In questo, abbiamo 2 classi, una è StatefulWidgete l'altra è il gestore dell'implementazione dello stato, ovvero State<YourWidget>. Quindi, se lo dico, possono rieseguire il build()metodo ancora e ancora in base agli eventi attivati.

Il diagramma sottostante aiuterà.

inserisci qui la descrizione dell'immagine


1

Quando scrivi un'app, crei comunemente nuovi widget che sono sottoclassi di StatelessWidget o StatefulWidget

Ecco alcune differenze tra StatelessWidgete StatefulWidgetwidget:

Widget apolidi:

  1. Un widget che ha uno stato immutabile.
  2. I widget stateless sono widget statici.
  3. Non dipendono da alcuna modifica dei dati o da qualsiasi modifica del comportamento.
  4. I widget stateless non hanno uno stato, verranno renderizzati una volta e non si aggiorneranno, ma verranno aggiornati solo quando i dati esterni cambiano.
  5. Per esempio: Text, Icon, RaisedButtonsono apolidi Widget.

Widget apolidi:

  1. Un widget che ha uno stato mutabile.
  2. I widget con stato sono widget dinamici.
  3. Possono essere aggiornati durante il runtime in base all'azione dell'utente o alla modifica dei dati.
  4. I widget con stato hanno uno stato interno e possono eseguire nuovamente il rendering se i dati di input cambiano o se cambia lo stato del widget.
  5. Per esempio: Checkbox, Radio Button, Slidersono Stateful Widget

1

disclaimer: - ha iniziato a lavorare su flutter dalla scorsa settimana :)

Il widget stateless e statefull ha il proprio ciclo di vita per creare e aggiornare l'interfaccia utente. tuttavia puoi usare sia stateless che statefull per rendere l'interfaccia utente ma praticamente statefull sono più utili quando ui è totalmente o parzialmente dipendente dai dati esterni (come - rendering di un elenco usando api) mentre l'uso di widget stateless per rendere statica ui come qualsiasi schermata di input è una buona pratica.


1
Penso che l'autore intendesse il contrario: · D
Roc Boronat

0

In parole semplici:

Come sappiamo ogni widget è una vista in bilico. Che ha le sue classi. Quando usiamo queste classi, ne creiamo un oggetto. Diamo valori alle loro diverse variabili / proprietà. Ex. Stiamo creando un widget di testo in modo da potergli assegnare Stringa, Colore, Dimensione carattere, Famiglia di caratteri. Quindi dando questo, stiamo definendo le sue proprietà mentre lo creiamo. Fino a questo punto, i widget Stateless o Stateful sono gli stessi ma,

Quando vogliamo cambiare / aggiornare le sue proprietà (diciamo Stringa o Colore) ancora e ancora in seguito, allora dovrebbe essere widget con stato.

E quando non vogliamo cambiare le sue proprietà dopo aver definito la prima volta è un widget senza stato.

ciò significa che ci preoccupiamo dei dati che il widget detiene / controlla / mostra.

Quindi Stateless è meno dati e Stateful è pieno di dati.

Ora, se definisci una classe che è senza stato significa che questa classe non si preoccupa / ha variabili in essa o dici dati nella sua classe cioè livello di classe ma potrebbe avere un altro widget / classe in essa che si preoccupa dei dati cioè è Stateful . Quindi non ha alcun impatto l'uno sull'altro.

Per favore correggimi se sbaglio qui.


0

Cosa sono i widget con stato e senza stato?

Widget senza stato: i widget senza stato vengono compilati solo quando si tratta di modifiche principali.

Widget con stato: i widget con stato completo mantengono lo stato del widget e possono essere ricostruiti quando lo stato cambia.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.