Escolha uma Página

Muitas dúvidas tem surgido sobre gerência de estados no Flutter, e quando falamos do mais famoso e eficiênte (o BLoC), acabamos confundindo as pessoas que estão começando nesse novo mundo da gerência de estados.
Esse post terá uma linguagem simples, explicará cada termo técnico para que você entenda de uma vez por todas o tão famigerado BLoC.

Gerência de estado

Se você já programou em qualquer outra linguagem, talvez nunca tenha ouvido falar em estado, pois bastava setar uma variável e a “mágica” acontecia, como por exemplo no Android Nativo:

textView.setText("Novo Texto no Android Nativo");

Só que as coisas não acontece do jeito que você pensa, por baixo dos panos toda a tela do aplicativo é reconstruida no próximo frame, é simplesmante tão rápido que você não vê acontecendo.
Agora imagine ter que reconstruir a tela inteira toda vez que precisar fazer uma alteração e em um dispositivo com hardware limitado (que é a realidade dos smartphones hoje). Logo entrariamos em um cenário de lenditão.

Por hora, vamos chamar a aplicação inteira de ESTADO ÚNICO, e reconstruimos esse estado (TELA INTEIRA) toda vez que precisamos fazer uma alteração. Vamos ao nosso exemplo começando com o nosso main.dart:

Iniciamos um projeto como qualquer outro, a diferença é que sempre coloca as páginas dentro de uma pasta “src” com o widget em um outro arquivo. Você pode fazer da maneira que achar melhor. Agora vamos dar uma olhada no home_page.dart :

A HomePage trata-se de um StatefulWidget, isso é, um widget com estado. Aqui temos a construção de uma tela que troca de cor ao arrastar o slider.

A regra de negócio desse app é bastante simples, mas atente-se a seguinte informação, temos 3 widgets que estão sendo alterados, porém o ESTADO inteiro é reconstruido com essa abordagem.
Note que ao mover o slide ele chama o método _onChangeValue(double v) o setState é chamado após atribuir a variável “v” a variável local _value, fazendo assim a reconstrução da tela no próximo frame agora com um novo value;

Note que estamos falando de construção de tela (view), isso significa que qualquer variável pode ser alterada em background e só quando o setState() é chamado a view é reconstruida.

Então define-se por “controle de estado” reconstruir apenas algumas partes da tela sem reiniciar todo o estado.

Agora que já entendemos o que é controle de estado, vamos então aprender a técnica para efetivamente termos esse controle e mais alguns outros beneficios.

O BLoC

Vamos então amarrar cada bloco da tela que precisa ser atualizado e assim não precisar atualizar toda a tela quando precisamos de um novo valor.

O BLoC significa Business Logic Component, ou seja, um Componete para Lógica de Negócio. Então a partir daqui temos alguns termos técnicos que gostaria de elucidar antes de proseguirmos.

View: Todo código que gera uma visualização.
Lógica de Negócio: Todo código que realiza cálculos internos antes de ser enviado para a view.

O Padrão BLoC faz mais que gerenciar estado, ele também divide bem o código da regra de negócio da view. Por exemplo, o PageHome é uma view, pois está gerando uma visualização para o usuário, e temos a variável _value e o método _onChangeValue que por essencia são parte da regra de negócio, então seria interessante criar uma classe apenas para esses itens. Vamos chamar esse classe de ValueBloc e colocar toda nossa regra de negócio para lá.

Perfeito, já fizemos a primeira parte do padrão BLoC, que é dividir o código da view da regra de negócio. Agora temos alguns erros na nossa HomePage, pois ainda precisamos conectar essas duas classes. E aqui vem a segunda parte do BLoC

Preparando a class BLoC

Agora já conseguimos ver uma organização no nosso código, e esse é o primeiro benefício do BLoC, divisão de tarefas, mas agora precisamos conecta-las para que tudo funcione.

Streams é a forma mais fácil de fazer essa conexão, pois ela nos oferece a possibilidade de poder reconstruir apenas um BLOCO de código da view que precisará ser reconstruido, e assim conseguir ter um controle de estado. Então temos ciência que uma Stream nada mais é que um fluxo, onde entra um dado e notifica todos os blocos que estão ouvindo essa stream.

A maneira mais fácil de fazer essa notificação é com o package bloc_pattern, que já vem com várias automatizações que precisamos para realizar o link entre a class Bloc e a View.
Para começar entre nessa página e siga as instruções de instalação do package.

Feito isso precisamos preparar o ValueBloc para se conectar com a View:

Só isso!
Temos um código pronto para atualizar partes da View, e conseguimos isso apenas herdando a class BlocBase e chamando o método notifyListeners() todas as vezes que precisamos que notifique o estado que uma parte dele tem dados novos e precisa ser reconstruido, nesse caso chamamos apenas quando recebemos um novo valor no onChangeValue.

Usando o package bloc_pattern, temos a possibilidade de fazer o ValueBloc ser escutado em qualquer lugar do aplicativo, e não necessariamente só no PageHome, para isso precisamos usar um recurso chamado de INJEÇÃO DE DEPENDÊNCIAS.

Injeção de dependências

Esse é um conceito amplamente utilizado em várias linguagens, trata-se de construir a instância de uma classe apenas quando ela for chamada e persistir ela na memória como um singleton (Instância Única), e é tudo que precisamos, pois não nos preocupamos em instanciar ou destruir uma classe na memório do nosso aplicativo, e podemos pegar essa instância em qualquer lugar do aplicativo.

Agora vamos injetar o nosso BLoC usando a Widget BlocProvider.
(OBS: é de suma importância que o BlocProvider seja um dos primeiros Widgets da nossa aplicação, sendo assim, iremos colocar ele antes do Widget MaterialApp.

Colocamos o BlocProvider como um dos primeiros Widget, e como filho (child) o MaterialApp, que iniciará nosso aplicativo normalmente.
O BlocProvider recebe uma lista de blocs, a qual apenas colocamos a injeção do nosso ValueBloc. Agora sim, vamos conectar a View com o BLoC.

Conectando a View com o Regra de Negócio

Agora simplesmente precisamos definir quais serão os BLOCOS da view(HomePage) que precisam ser reconstruidos após uma alteração na nossa class BLoC.


Temos 3 coisas que mudam, o Slider, o Texto e a Cor de Fundo da View. A nossa missão aqui é modificar o Slider e o Texto sem que a tela mude de cor, isso significa que reconstruimos apenas os dois sem reconstruir o estado inteiro.

Então vamos usar o Widget Consumer do bloc_pattern e passar como filho os widgets que serão atualizados.

Note que colocamos os Widgets que vão ser reconstruidos dentro de um Consumer<ValueBloc>, e ele passa dois parametros, o context e a instância do bloc, e assim podemos acessar as propriedades e métodos desse bloc, como fizemos no Slider, em que acessamos o método valueBloc.onChangeValue toda vez que o slider for mudado.

Também podemos acessar todos os nossos BLoCs injetados usando o BlocProvider.getBloc<T>();

ValueBloc valueBloc = BlocProvider.getBloc<ValueBloc>();

Vamos usar essa variável para setar o valor da cor do background e assim poder constatar que nossa gerência de estado está funcionando, pois atualizará dois Widgets mas não o background


ValueBloc valueBloc = BlocProvider.getBloc&lt;ValueBloc>();

return Material(
      color: Color.lerp(Colors.red, Colors.purple, valueBloc.value),

Agora vamos ver se realmente estamos controlando o estado do HomePage com BLoC. O Código da HomePage ficou assim:

E o resultado da aplicação ficou assim:

O link do projeto está aqui, (vou deixar preparado para o Flutter Desktop para quem quiser testar).

Agora temos uma gerência simples de Estado usando BLoC!
No próximo post iremos nos aprofundar mais nas Streams e acrescentar Programação Reativa que nosso BLoC tenha super-poderes. Até lá!