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:

Inicie o Flutter App Emulator

O número aumenta à medida que o botão é pressionado:

Demonstração de flutuação pressionada do botão de aumento de número

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:

Decrement Incremen t Botão contador

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:

Mix Match State Management

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:

Dummy Container Widget

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:

Complete Flutter State Management 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

The post Flutter state management methods: An overview appeared first on LogRocket Blog.

Source link