StatefulWidget vs StatelessWidget.
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 stateless
widget è 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:
- 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();
- montato == true - Tutti i widget hanno una
this.mounted
proprietà bool . Diventa vero quando buildContext
viene assegnato. È un errore chiamare setState
quando 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;
- initState () - Questo è il primo metodo chiamato quando il widget viene creato (dopo il costruttore della classe, ovviamente).
initState
viene 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 ChangeNotifiers
o qualsiasi altro oggetto che potrebbe modificare i dati su questo widget.
@override
initState() {
super.initState();
cartItemStream.listen((data) {
_updateWidget(data);
});
}
- didChangeDependencies () - Chiamato quando una dipendenza di questo oggetto State cambia.
Questo metodo viene chiamato anche immediatamente dopo initState
. È sicuro chiamare BuildContext.inheritFromWidgetOfExactType
da 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() { }
- 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"); } ...
}
- 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) { }
- 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 });
- 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() { }
- 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; }());
}
Per maggiori informazioni vai qui qui , qui