Padrão BLoC com um exemplo simples

E novamente sobre o BLoC usando o exemplo clássico do contador Flutter.


Lendo alguns artigos sobre programação reativa e usando o padrão BLoC em aplicativos, percebi que não estava alcançando algo. Como de costume, não há tempo suficiente para tudo, mas agora houve uma hora livre e há força - decidiu-se que vou escrever o aplicativo Flutter mais simples com o padrão BLoC.


Sob aplicações animashka cat e explicações, por que eu escrevi dessa maneira. Muito interessante é a opinião da comunidade.


imagem


Sim, já escrevemos sobre esse padrão muitas vezes, mas, de qualquer maneira, não há instruções e regras claras para usá-lo, e muitas vezes surge a questão de como implementar corretamente a lógica no aplicativo.


O objetivo do artigo é trazer um pouco de clareza para mim e, espero, para os leitores.


Portanto, a definição do padrão, conforme expressa pelos engenheiros do Google - BLOC, é uma classe simples na qual:


  1. todos os fluxos de saídas
  2. todas as entradas são fluxos
  3. essa classe deve remover a lógica da interface visual

Para implementar esse padrão, se necessário, podemos usar a biblioteca rxdart , mas não podemos usá-lo.


Isso não removerá a reatividade, como você imagina. Enquanto os criadores do pacote escrevem, o rxdart adiciona funcionalidade aos recursos avançados já incorporados da linguagem Dart ao trabalhar com fluxos.


App



Portanto, pegamos o aplicativo com contadores, que são criados automaticamente quando o projeto é criado e tentamos reescrevê-lo usando o padrão BLoC.


Tarefas:


  1. Remova toda a lógica dos widgets
  2. Na classe BLoC, receba apenas fluxos de entrada e produza apenas fluxos de saída. Por exemplo, a função proposta nos comentários ao artigo .

imagem


não nos convém, pois viola a regra de passar apenas fluxos para a classe.


Solução:


  1. Nós removemos toda a lógica dos widgets. Tornamos a classe Stateless e paramos de atualizar o estado com setState.
  2. Exibimos as leituras do medidor em diferentes locais usando o widget interno, que é feito especificamente para exibir dados de fluxos - StreamBuilder.

class MyHomePage extends StatelessWidget { CounterBloc counterBloc = CounterBloc(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: StreamBuilder<int>( stream: counterBloc.pressedCount, builder: (context, snapshot) { return Text( 'Flutter Counter Bloc Example - ${snapshot.data.toString()}', ); }), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'You have pushed the button this many times:', ), StreamBuilder<int>( stream: counterBloc.pressedCount, builder: (context, snapshot) { return Text( '${snapshot.data.toString()}', style: Theme.of(context).textTheme.display1, ); }), ], ), ), floatingActionButton: Container( width: 100.0, height: 100.0, child: FloatingActionButton( onPressed: () { counterBloc.incrementCounter.add(null); }, tooltip: 'Increment', child: Text( "+ \n send \n to BLoC", textAlign: TextAlign.center, ), ), ), ); } } 

  1. Criamos uma classe separada onde implementamos o padrão BLoC:
    3.1 Todas as propriedades e métodos de classe estão ocultos.
    3.2 Para receber e transferir o estado, usamos fluxos visíveis de fora usando getters (mas aqui está um artigo interessante sobre eles ).

 class CounterBloc { int _counter; CounterBloc() { _counter = 1; _actionController.stream.listen(_increaseStream); } final _counterStream = BehaviorSubject<int>.seeded(1); Stream get pressedCount => _counterStream.stream; Sink get _addValue => _counterStream.sink; StreamController _actionController = StreamController(); StreamSink get incrementCounter => _actionController.sink; void _increaseStream(data) { _counter += 1; _addValue.add(_counter); } void dispose() { _counterStream.close(); _actionController.close(); } } 

Isso é tudo, temos um exemplo prático, no qual transmitimos e recebemos estados em fluxos e exibimos dados nos widgets necessários sem aplicar nenhuma lógica na parte visual.


Assim, podemos separar todos os cálculos, transferências de dados, etc. da interface. Por exemplo, se você adicionar rótulos diferentes ao contador, dependendo da quantidade e retirá-los de um banco de dados externo, toda essa lógica já passará pelo BLoC - nossa interface não saberá nada sobre isso.


Nota 1: observe que estamos criando uma instância da classe> CounterBloc counterBloc = CounterBloc (); e então obtemos dados dele. Se precisarmos desses dados em telas diferentes (em classes espaçadas), poderemos usar widgets herdados para transferência ou criar Singleton da nossa classe.


Código de exemplo do Github


Boa codificação para todos!


Continuação


Na sequência, transferimos o estado em diferentes telas, salvamos os dados na memória permanente do telefone, testamos o BLoC https://habr.com/en/post/485002/

Source: https://habr.com/ru/post/pt475404/


All Articles