O gerenciamento de estado é um dos principais recursos que uma estrutura de IU deve implementar-e bem implementar. É por esse motivo que muitos desenvolvedores acabaram criando bibliotecas de gerenciamento de estado dedicadas; a solução integrada não era suficiente para eles, ou eles queriam ajustá-la ao seu gosto.
Desde então, as estruturas de interface do usuário aprimoraram seu jogo para nivelar o campo de jogo. Suas soluções de gerenciamento de estado integradas agora podem corresponder ao desempenho de soluções externas existentes. React, por exemplo, introduziu Ganchos e Contexto para competir com React-Redux.
O mesmo aconteceu no Flutter: ele oferece vários métodos integrados para gerenciar o estado do aplicativo. Neste artigo, veremos algumas maneiras básicas, porém poderosas, de gerenciar o estado em nossos aplicativos Flutter.
Usando setState
no Flutter
Se você vier do React, descobrirá que este método de gerenciamento de estado no Flutter é semelhante ao uso do gancho useState
.
setState
gerencia apenas o estado no widget em que foi declarado-assim como no React, em que o gancho useState
gerencia o estado local apenas no componente em que foi criado. Este tipo de gerenciamento de estado é denominado e estado temporário . Aqui, este estado é controlado usando StatefulWidget
e o método setState ()
.
Usando o próprio widget para gerenciar o estado
Vamos verificar alguns exemplos de como o setState
funciona criando um aplicativo de contador simples. O aplicativo terá um número de contador que podemos aumentar e diminuir clicando nos botões.
Primeiro, crie o scaffold de um projeto Flutter executando o seguinte comando:
vibração criar meuaplicativo
Isso cria uma pasta de projeto Flutter com o nome myapp
. Agora vamos executar o projeto em um servidor:
vibração execute meu aplicativo
Em nossa pasta de projeto, devemos ver um arquivo main.dart
. Este é o arquivo principal do aplicativo Flutter. Limpe o conteúdo do arquivo e adicione o código abaixo:
import'package: flutter/material.dart'; void main () { runApp (MyApp ()); } class MyApp extends StatelessWidget { @sobrepor Construção de widget (contexto BuildContext) { return MaterialApp ( título:'Demonstração do Flutter', tema: ThemeData ( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), casa: Scaffold ( appBar: AppBar ( título: Texto ("Demonstração de gerenciamento de estado"), ), body: CounterPage (title:'Flutter Demo')), ); } }
Tudo no Flutter é um widget. MyApp
é o widget de entrada/raiz de nosso aplicativo. No prop body
, observe que estamos renderizando um widget CounterPage
. Este é um widget com estado que estende a classe StatefulWidget
.
StatefulWidgets
são usados para gerenciar estados locais em widgets. Eles criam um objeto State
associado e também contêm variáveis imutáveis.
Aqui está um exemplo:
class NotificationCounter extends StatefulWidget { nome final da string; NotificationCounter ({this.name}); @sobrepor _NotificationCounterState createState ()=& amp; gt; _NotificationCounterState (); }
A variável name
acima é uma variável imutável. StatefulWidget
contém apenas variáveis imutáveis e o objeto State
.
Vamos ver nosso código CounterPage
:
class CounterPage extends StatefulWidget { CounterPage ({Key key, this.title}): super (key: key); título final da string; @sobrepor CounterPageState createState ()=& amp; gt; CounterPageState (); }
O método createState
cria um objeto de CounterPageState
e o retorna. O método createState
é chamado quando o widget é construído.
Vamos ver o código para CounterPageState
:
a classe CounterPageState estende State & amp; lt; CounterPage & amp; gt; { int _contador=0; void _incrementCounter () { setState (() { _counter ++; }); } @sobrepor Construção de widget (contexto BuildContext) { return Scaffold ( appBar: AppBar ( título: Texto (widget.title), ), corpo: Centro ( filho: coluna ( mainAxisAlignment: MainAxisAlignment.center, filhos: & amp; lt; Widget & amp; gt; [ Fileira( mainAxisAlignment: MainAxisAlignment.center, crianças: [ Texto( 'Balcão:', style: Theme.of (context).textTheme.headline4, ), Texto( '$ _counter', style: Theme.of (context).textTheme.headline4, ), ], ), FlatButton ( cor: Colors.orange, child: Text ('Increment Counter', style: TextStyle (color: Colors.white)), onPressed: _incrementCounter, ) ], ), ) ); } }
CounterPageState
tem uma variável mutável _counter
, que armazena o número do contador e pode ser alterada durante a vida útil do widget.
O método build
é chamado quando o widget deve ser construído. Ele retorna a IU do widget e appBar
-> title
define o que será exibido na barra de aplicativos da página. O corpo
define a IU do corpo do widget.
Geralmente, este widget exibirá o texto Contador: , a variável _counter
em uma linha e um botão na próxima linha. O botão tem um evento onPressed
definido, semelhante ao evento onclick
em HTML.
A função _incrementCounter
chama setState
quando o botão é pressionado. Essa chamada de método informa ao Flutter que um estado dentro de um widget foi alterado e o widget deve ser redesenhado. O argumento da função para setState
incrementa a variável _counter
.
void _incrementCounter () { setState (() { _counter ++; }); }
Portanto, sempre que clicamos no botão Incrementar contador , o _counter
é incrementado e setState
é chamado, o que diz ao Flutter para reconstruir o widget árvore. O método build
do CounterPageState
é chamado, e a árvore do widget no widget é então reconstruída e re-renderizada na IU (NB, apenas as partes que mudaram são refeitas-render).
Se lançarmos nosso aplicativo em um emulador, ele deverá se parecer com isto:
O número aumenta à medida que o botão é pressionado:
Agora vamos adicionar um botão de decremento. Este botão diminuirá o contador e refletirá a atualização na tela. Como fazemos isso?
Simples: vamos adicionar um novo FlatButton
com o texto Decrement Counter
e definir um evento onPressed
nele. Vamos criar um método _decrementCounter
e defini-lo como um manipulador para o evento onPressed
.
Este método _decrementCounter
diminuirá o _counter
em 1 quando chamado e chamará o setState
para atualizar a IU:
a classe CounterPageState estende State & amp; lt; CounterPage & amp; gt; { int _contador=0; void _incrementCounter () { setState (() { _counter ++; }); } void _decrementCounter () { setState (() { _balcão--; }); } @sobrepor Construção de widget (contexto BuildContext) { return Scaffold ( appBar: AppBar ( título: Texto (widget.title), ), corpo: Centro ( filho: coluna ( mainAxisAlignment: MainAxisAlignment.center, filhos: & amp; lt; Widget & amp; gt; [ Fileira( mainAxisAlignment: MainAxisAlignment.center, crianças: [ Texto( 'Balcão:', style: Theme.of (context).textTheme.headline4, ), Texto( '$ _counter', style: Theme.of (context).textTheme.headline4, ), ], ), FlatButton ( cor: Colors.orange, filho: Texto ('Contador de incrementos', style: TextStyle (color: Colors.white)), onPressed: _incrementCounter, ), FlatButton ( color: Colors.red, filho: Texto ('Decrementar Contador', style: TextStyle (color: Colors.white)), onPressed: _decrementCounter, ) ], ), )); } }
Damos ao botão de decremento um fundo vermelho e coloque-o abaixo do botão de incremento . O método _decrementCounter
é definido como seu evento onPressed
. O método _decrementCounter
diminui _counter
cada vez que é chamado e chama o setState
para acionar as atualizações da IU.
Veja a demonstração abaixo:
Agora que vimos como usar o próprio widget para gerenciar o estado, vamos examinar duas outras opções: usar o widget pai para gerenciar o estado e usar um método de combinação e correspondência.
Usando um widget pai para gerenciar o estado
Nesta abordagem, o pai do widget mantém as variáveis de estado e gerencia o estado. O pai informa ao widget quando atualizar, passando as variáveis de estado para o widget filho. Os métodos usados para alterar o estado também são passados para o widget filho, que o widget pode chamar para alterar o estado e se atualizar.
Podemos reescrever nosso exemplo de contador
acima para usar essa abordagem. Teremos um widget sem estado cujo trabalho é renderizar a IU. Crie uma classe Counter
e preencha como abaixo:
class Counter extends StatelessWidget { contador final; final decrementCounter; final incrementCounter; Balcão( {Chave chave, this.contador: 0, @required this.decrementCounter, @required this.incrementCounter}) : super (tecla: tecla); @sobrepor Construção de widget (contexto BuildContext) { return Scaffold ( corpo: coluna ( mainAxisAlignment: MainAxisAlignment.center, filhos: & amp; lt; Widget & amp; gt; [ Fileira( mainAxisAlignment: MainAxisAlignment.center, crianças: [ Texto( 'Balcão:', style: Theme.of (context).textTheme.headline4, ), Texto( '$ counter', style: Theme.of (context).textTheme.headline4, ), ], ), FlatButton ( cor: Colors.orange, filho: Text ('Increment Counter', style: TextStyle (color: Colors.white)), onPressed: () { incrementCounter (); }, ), FlatButton ( color: Colors.red, filho: Texto ('Decrementar contador', estilo: TextStyle (color: Colors.white)), onPressed: () { decrementCounter (); }, ) ], )); } }
Novamente, este é um widget sem estado, portanto, não tem estado; ele apenas renderiza o que é passado para ele.
Observe que movemos o trabalho de renderização do contador para este widget. O contador é passado para ele via this.counter
, e as funções de decremento e incremento via this.decrementCounter
e this.incrementCounter
, respectivamente. Todos eles são passados do widget pai, CounterPageState
.
Agora, o widget CounterPageState
ficará assim:
a classe CounterPageState estende State & amp; lt; CounterPage & amp; gt; { //... @sobrepor Construção de widget (contexto BuildContext) { return Scaffold ( //... corpo: Centro ( criança: Contador ( contador: _counter, decrementCounter: _decrementCounter, incrementCounter: _incrementCounter ) ) ); } }
O Contador
é renderizado agora por CounterPageState
, a IU que ele renderizou anteriormente agora está sendo tratada pelo novo widget Contador
.
Aqui, o estado _counter
é passado para o widget Counter
no counter
prop. O widget Contador
acessará o contador por meio do contador
em seu corpo.
Além disso, os métodos _decrementCounter
e _incrementCounter
são passados para o widget Contador
. Eles são chamados a partir do widget Counter
para atualizar o estado _counter
no widget CounterPageState
, o que fará com que o CounterPageState
para reconstruir e renderizar novamente o Contador
para exibir o estado recém-alterado.
Gerenciamento de estado mix-and-match
Nesta abordagem, o widget pai gerencia alguns estados, enquanto o widget filho gerencia outro aspecto do estado. Para demonstrar isso, faremos nosso widget Counter
manter um estado, o que o torna um StatefulWidget
.
Rastrearemos o número de vezes que o botão de incremento e o botão de diminuição são clicados e mantêm o número em dois estados.
Agora, vamos transformar o widget Contador
em um widget com estado:
class Counter extends StatefulWidget { contador final; final decrementCounter; final incrementCounter; Balcão( {Chave chave, this.contador: 0, @required this.decrementCounter, @required this.incrementCounter}) : super (tecla: tecla); @sobrepor CounterState createState ()=& amp; gt; CounterState (); }
Podemos ver que o método createState
retorna um objeto CounterState
. Vamos dar uma olhada na classe CounterState
:
classe CounterState estende State & amp; lt; Counter & amp; gt; { var incrButtonClicked=0; var decreButtonClicked=0; @sobrepor Construção de widget (contexto BuildContext) { return Scaffold ( corpo: coluna ( mainAxisAlignment: MainAxisAlignment.center, filhos: & amp; lt; Widget & amp; gt; [ Fileira( mainAxisAlignment: MainAxisAlignment.center, crianças: [ Texto( 'Balcão:', style: Theme.of (context).textTheme.headline4, ), Texto( widget.contador.toString (), style: Theme.of (context).textTheme.headline4, ), ], ), Coluna( mainAxisAlignment: MainAxisAlignment.center, crianças: [ Texto ("'Botão de incremento'clicado $ incrButtonClicked times"), Texto ("'Botão de redução'clicado $ decreButtonClicked vezes") ], ), FlatButton ( cor: Colors.orange, filho: Text ('Increment Counter', style: TextStyle (color: Colors.white)), onPressed: () { widget.incrementCounter (); setState (() { incrButtonClicked ++; }); }, ), FlatButton ( color: Colors.red, filho: Texto ('Decrementar contador', estilo: TextStyle (color: Colors.white)), onPressed: () { widget.decrementCounter (); setState (() { decreButtonClicked ++; }); }, ) ], )); } }
Observe que a IU anterior do widget Contador
está aqui. Adicionamos os estados incrButtonClicked
e decreButtonClicked
para conter o número de vezes que os botões foram pressionados. Também adicionamos um widget de Coluna
para exibir widgets de Texto
em colunas centralizadas no eixo principal. Esses widgets Texto
exibirão o número de vezes que cada botão foi clicado.
Agora, no manipulador de eventos onPressed
de cada botão, chamamos o método incrementCounter
ou decrementCounter
por meio do widget objeto. Usamos o objeto
widget
para obter acesso às variáveis pai em um widget com estado. Em seguida, chamamos o método setState
, que aumenta ou diminui as variáveis de estado incrButtonClicked
e decreButtonClicked
.
Portanto, podemos ver aqui que temos uma abordagem de gerenciamento de estado de combinação: o widget pai lida com o estado contador
, enquanto o widget filho lida com o estado clicado.
Veja a demonstração abaixo:
InheritedModel
e InheritedWidget
Esta técnica usa uma abordagem de comunicação entre widgets pai e filho. Os dados são configurados no widget pai e os widgets filhos podem acessar os dados do widget pai, fazendo com que o estado do widget seja transmitido perfeitamente.
Este tipo de gerenciamento de estado é semelhante ao uso da classe Service
no Angular e também tem semelhança com a API de contexto do React.
InheritedWidget
InheritedWidget
é uma classe base no Flutter que é usada para propagar informações na árvore de widgets.
É assim que funciona: um InheritedWidget
envolve uma árvore de widgets. Agora, os widgets na árvore podem se referir a InheritedWidget
para acessar as variáveis públicas nele, passando os dados pela árvore. Os dados a serem mantidos pelo InheritedWidget
são passados para ele por meio de seu construtor.
InheritedWidget
é muito útil quando temos que passar dados por uma longa cadeia de widgets apenas para usá-los em um widget. Por exemplo, temos nossa árvore de widgets como esta:
MyApp | v CounterPage | v DummyContainer1 | v DummmyContainer2 | v Balcão
A CounterPage
tem um estado counter
com os métodos incrementCounter
e incrementCounter
. Queremos exibir o contador
na IU com o widget Contador
. Para fazer isso, temos que passar o estado counter
e os dois métodos para o widget Counter
.
Primeiro, a partir do widget CounterPage
, iremos renderizar o widget DummyContainer
, passando o counter
e os dois métodos como argumentos para seu construtor. Em seguida, DummyContainer1
renderizará DummyContainer2
e passará o estado counter
e os dois métodos para o construtor DummyContainer2
como argumentos. Finalmente, DummyContainer2
renderizará Counter
e passará o contador e os métodos para ele.
Com InheritedWidget
, podemos acabar com todo esse trabalho de adereços. Com InheritedWidget
, definiremos o counter
e os dois métodos nele. O InheritedWidget
renderizará o DummyContainer1
e o CounterPage
renderizará o InheritedWidget
. CounterPage
definirá o counter
e os métodos como dados no InheritedWidget
.
MyApp | v CounterPage | v MyInheritedWidget | v DummyContainer1 | v DummmyContainer2 | v Balcão
Esta é a aparência da árvore com a inclusão de InheritedWidget
.
Vamos codificar! Começaremos com CounterPage
:
class CounterPage extends StatefulWidget { CounterPage ({Key key, this.title}): super (key: key); título final da string; @sobrepor CounterPageState createState ()=& amp; gt; CounterPageState (); CounterPageState estático de (contexto BuildContext) { return context.dependOnInheritedWidgetOfExactType & amp; lt; MyInheritedWidget & amp; gt; (). data; } }
Adicionamos um método estático
de
. Este método usa o context
para retornar um InheritedWidget
usando a chamada do método dependOnInheritedWidgetOfExactType
. Este método retorna o Inherited``W``idget
mais próximo na árvore de widgets de um tipo exato; neste caso, queremos um tipo MyInheritedWidget
.
Agora, em nosso CounterPageState
, iremos renderizar MyInheritedWidget
e, dentro dele, renderizaremos o widget DummyContainer1
.
a classe CounterPageState estende State & amp; lt; CounterPage & amp; gt; { //... @sobrepor Construção de widget (contexto BuildContext) { return Scaffold ( appBar: AppBar ( título: Texto (widget.title), ), corpo: Centro ( filho: MyInheritedWidget ( filho: DummyContainer1 (), dados: este ) ) ); } }
O parâmetro data
contém this
, o que significa que as propriedades públicas de CounterPageState
são acessíveis a MyInheritedWidget
por meio do data
prop. Fizemos isso porque queremos que o _counter
e os dois métodos _incrementCounter
e _decrementCounter
sejam referenciados por um InheritedWidget
. Com isso, podemos usar o InheritedWidget
para acessar o estado counter
e os métodos em qualquer lugar na árvore do widget.
Vamos criar os widgets MyInheritedWidget
, DummyContainer1
e DummyContainer2
.
class MyInheritedWidget extends InheritedWidget { dados finais do CounterPageState; MyInheritedWidget ({ Chave chave, @required Widget filho, @required this.data, }): super (chave: chave, filho: filho); @sobrepor bool updateShouldNotify (InheritedWidget oldWidget) { return true; } }
Temos uma propriedade data
e um objeto CounterPageState
. Este é o objeto da classe que passamos no CounterPageState
. O método updateShouldNotify
determina se o InheritedWidget
reconstruirá a árvore de widgets abaixo dele. Se retornar verdadeiro, a árvore do widget será reconstruída; se retornar falso, a árvore do widget não será reconstruída quando o estado mudar.
class DummyContainer1 extends StatelessWidget { const DummyContainer1 ({Key key}): super (key: key); @sobrepor Construção de widget (contexto BuildContext) { return DummyContainer2 (); } }
Este widget DummyContainer1
renderiza o widget DummyContainer2
.
class DummyContainer2 extends StatelessWidget { const DummyContainer2 ({Key key}): super (key: key); @sobrepor Construção de widget (contexto BuildContext) { return Counter (); } }
O widget DummyContainer2
, por sua vez, renderiza o widget Contador
.
Agora, vamos ver nosso widget Contador
:
class Counter extends StatefulWidget { @sobrepor CounterState createState ()=& amp; gt; CounterState (); }
Ele apenas implementa o método createState
:
classe CounterState estende State & amp; lt; Counter & amp; gt; { var incrButtonClicked=0; var decreButtonClicked=0; var counter; Dados CounterPageState; @sobrepor void didChangeDependencies () { super.didChangeDependencies (); dados=CounterPage.of (contexto); contador=dados._contador; } @sobrepor Construção de widget (contexto BuildContext) { return Scaffold ( corpo: coluna ( mainAxisAlignment: MainAxisAlignment.center, filhos: & amp; lt; Widget & amp; gt; [ Fileira( mainAxisAlignment: MainAxisAlignment.center, crianças: [ Texto( 'Balcão:', style: Theme.of (context).textTheme.headline4, ), Texto( counter.toString (), style: Theme.of (context).textTheme.headline4, ), ], ), Coluna( mainAxisAlignment: MainAxisAlignment.center, crianças: [ Texto ("'Botão de incremento'clicado $ incrButtonClicked times"), Texto ("'Botão de redução'clicado $ decreButtonClicked vezes") ], ), FlatButton ( cor: Colors.orange, filho: Text ('Increment Counter', style: TextStyle (color: Colors.white)), onPressed: () { data._incrementCounter (); setState (() { incrButtonClicked ++; }); }, ), FlatButton ( color: Colors.red, filho: Texto ('Decrementar contador', estilo: TextStyle (color: Colors.white)), onPressed: () { data._decrementCounter (); setState (() { decreButtonClicked ++; }); }, ) ], )); } }
Observe que removemos os adereços do construtor. Usamos CounterPageState data=CounterPage.of (context);
para obter o MyInheritedWidget
na variável data
. A partir daí, podemos acessar as propriedades e métodos públicos em MyInheritedWidget
. Observe como acessamos as propriedades _counter
, _incrementCounter
e _decrementCounter
da variável data
.
Essas são as propriedades que foram armazenadas em MyInheritedWidget
de CounterPageState
, então, uma vez que referenciarmos MyInheritedWidget
, podemos obter essas propriedades de qualquer lugar na árvore de widgets. É assim que os dados são passados e acessados por meio de um InheritedWidget
em qualquer lugar na árvore do widget.
Esta é a demonstração:
InheritedModel
InheritedModel
funciona da mesma maneira que InheritedWidget
: ele gerencia o estado e propaga o estado em sua árvore de widgets. Mas InheritedModel
é um pouco diferente, pois permite maior controle sobre os gatilhos de detecção de mudança e notificação de atualização, que podem ser configurados para responder quando dados específicos mudam.
InheritedModel
é fácil de implementar. Vamos reescrever nosso exemplo Counter
acima para usar InheritedModel
. Surpreendentemente, o código será quase o mesmo.
Primeiro, altere MyInheritedWidget
para MyInheritedModel
:
class MyInheritedModel extends InheritedModel & amp; lt; String & amp; gt; { dados finais do CounterPageState; MyInheritedModel ({ Chave chave, @required Widget filho, @required this.data, }): super (chave: chave, filho: filho); @sobrepor bool updateShouldNotify (MyInheritedModel old) { return true; } @sobrepor bool updateShouldNotifyDependent (MyInheritedModel old, Set & amp; lt; String & amp; gt; aspect) { return true; } estático MyInheritedModel de (BuildContext context, String aspect) { return InheritedModel.inheritFrom & amp; lt; MyInheritedModel & amp; gt; (contexto, aspecto: aspecto); } }
Ainda o mesmo; o principal aqui é o método estático
de
. Ele retorna uma instância de si mesmo para que possamos usá-lo para acessar suas propriedades públicas. dados finais do CounterPageState;
é a propriedade que queremos disponibilizar publicamente-é o estado que será propagado por este InheritedModel
em sua árvore de widgets. Observe que seu valor é definido pelo parâmetro this.data
no construtor.
A seguir, atualizamos nosso CounterState
de acordo:
classe CounterState estende State & amp; lt; Counter & amp; gt; { var incrButtonClicked=0; var decreButtonClicked=0; var counter; MyInheritedModel inheritedModel; @sobrepor Construção de widget (contexto BuildContext) { inheritedModel=MyInheritedModel.of (context,""); counter=inheritedModel.data._counter; return Scaffold ( corpo: coluna ( mainAxisAlignment: MainAxisAlignment.center, filhos: & amp; lt; Widget & amp; gt; [ Fileira( mainAxisAlignment: MainAxisAlignment.center, crianças: [ Texto( 'Balcão:', style: Theme.of (context).textTheme.headline4, ), Texto( counter.toString (), style: Theme.of (context).textTheme.headline4, ), ], ), Coluna( mainAxisAlignment: MainAxisAlignment.center, crianças: [ Texto ("'Botão de incremento'clicado $ incrButtonClicked times"), Texto ("'Botão de redução'clicado $ decreButtonClicked vezes") ], ), FlatButton ( cor: Colors.orange, filho: Text('Increment Counter', style: TextStyle(color: Colors.white)), onPressed: () { inheritedModel.data._incrementCounter(); setState(() { incrButtonClicked++; }); }, ), FlatButton( color: Colors.red, child: Text('Decrement Counter', style: TextStyle(color: Colors.white)), onPressed: () { inheritedModel.data._decrementCounter(); setState(() { decreButtonClicked++; }); }, ) ], )); } }
Here we have MyInheritedModel inheritedModel;
, and we call inheritedModel=MyInheritedModel.of(context,"");
in the build()
method to get the instance of MyInheritedModel
.
Now, from inheritedModel
, we can access the final CounterPageState data;
property to get the counter
, _incrementCounter
, and _decrementCounter
properties in the CounterPageState
widget.
The counter state is received from counter=inheritedModel.data._counter;
and then converted to a string before it’s displayed.
The _incrementCounter
, _decrementCounter
methods are called via inheritedModel.data._incrementCounter();
and inheritedModel.data._decrementCounter();
to increase and decrease the button click times, respectively.
This will be the Counter
code:
class Counter extends StatefulWidget { @override CounterState createState()=> CounterState(); }
Nothing much to note here; just implement the createState
method and return an instance of the CounterState
widget.
Now, here’s our CounterPageState
:
class CounterPageState extends State<CounterPage> { int _counter=0; void _incrementCounter() { setState(() { _counter++; }); } void _decrementCounter() { setState(() { _counter--; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: MyInheritedModel( child: DummyContainer1(), data: this ) ) ); } }
CounterPageState
mounts MyInheritedModel
. The instance of the CounterPageState
is passed to its constructor via the data
param. This is how we’re able to access the public properties of CounterPageState
from MyInheritedModel
.
And here’s the demo:
Conclusion
We’ve covered the basics of state management using Flutter’s inbuilt mechanism. We started by analyzing what state management is and how it is ideal for any UI framework to have. Next, we looked at setState
and how its compares to React’s useState
Hook. We illustrated by example how setState
works and how we can use it to build real-world apps.
We then discussed InheritedWidget
and saw how we can declare a state and propagate it down the widget tree. Widgets down the tree can subscribe to the state to get the updates whenever the state changes.
Similar to InheritedWidget
, we looked at InheritedModel
, which propagates state down the widget tree. The difference here is that we can choose the state we wish to be notified of when it changes.
Further reading
- Adding interactivity to your Flutter app
- Intro to state management
- How does Flutter InheritedWidget work?
The post Flutter state management methods: An overview appeared first on LogRocket Blog.