BLoC (Business Logic Component) — um padrão de gerenciamento de estado para Flutter, apresentado pelo Google em 2018 no DartConf. BLoC separa a lógica de negócio da interface do usuário através de fluxos reativos (Stream): a UI envia um Event, o BLoC processa e retorna um novo State através do Stream. De acordo com pub.dev, o pacote flutter_bloc acumulou mais de 11 mil curtidas e é usado em milhares de aplicações Flutter.
Principais pontos
BLoC (Business Logic Component) — um padrão arquitetural para Flutter no qual a lógica de negócio é extraída para uma classe separada, isolada da UI. BLoC recebe dados de entrada através de um fluxo de eventos (Event) e produz dados de saída através de um fluxo de estados (State). A camada de apresentação (Widget) apenas se inscreve no fluxo de State e renderiza a UI, nunca executando a lógica de negócio diretamente.
O conceito BLoC é baseado em programação reativa e no padrão Observer. Cada componente BLoC é um módulo separado com um contrato claro: um conjunto conhecido de Events (o que pode acontecer) e um conjunto conhecido de States (o que pode ser exibido). Um desenvolvedor não pode "acidentalmente" alterar o estado da UI — apenas através de um Event específico. Isso torna o código previsível e testável.
De acordo com a pesquisa Flutter Community 2025, BLoC ocupa o segundo lugar em popularidade entre as soluções de gerenciamento de estado no Flutter, depois do Provider. Principais vantagens: tipagem forte, isolamento de lógica, suporte nativo a Stream, ecossistema rico de utilitários (BlocProvider, BlocListener, BlocSelector).
A arquitetura BLoC é construída em torno de três entidades: Event (entrada), Bloc (processador) e State (saída). O Widget envia um Event através do método add(). O Bloc recebe o Event no método mapEventToState ou on<Event>, executa a lógica de negócio e emite um novo State via yield. O Widget recebe o State através de um Stream e reconstrói.
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0);
@override
Stream<int> mapEventToState(CounterEvent event) async* {
if (event is Increment) {
yield state + 1;
} else if (event is Decrement) {
yield state - 1;
}
}
}Segurança de tipos: Bloc é parametrizado com dois tipos — Event e State. O compilador Dart verifica se o Widget chama apenas Events declarados e se o Bloc retorna apenas States declarados. Erros de tempo de execução como "Action desconhecida" são eliminados.
Close e Dispose: Bloc implementa a interface Closeable. Quando um widget é destruído, o Bloc fecha automaticamente o Stream através do método close(). Vazamentos de assinaturas reativas são impossíveis — BlocProvider gerencia o ciclo de vida do Bloc, vinculando-o a uma rota ou página.
Cubit é uma implementação simplificada do Bloc sem Event, apresentada no pacote flutter_bloc 6.0. Cubit declara métodos diretamente em vez de classes Event: increment(), fetchData(). Internamente, Cubit usa o mesmo mecanismo baseado em Stream, mas oculta a camada de Event. Isso reduz o boilerplate em 40-50% para cenários simples.
| Característica | Bloc | Cubit |
|---|---|---|
| Classes Event | Obrigatórias | Não necessárias |
| Boilerplate | Alto | Baixo |
| Rastreamento de ações | Via tipo Event | Apenas nome do método |
| Ideal para | Cenários complexos | Estados simples |
| Analítica | Automática por Event | Manual |
Quando escolher Cubit: estado com 2-3 variantes (loading, loaded, error), formulários simples, contadores, estados de UI (aberto/fechado). Quando escolher Bloc: lógica de negócio complexa com múltiplas ações: processamento de pedidos, autorização, sincronização de dados. Bloc fornece rastreamento detalhado de cada ação através de Event — cada chamada é registrada no BlocObserver.
BlocObserver — um observador global que rastreia todos os Bloc e Cubit na aplicação. Permite registrar Event, State, erros e transições. Basta conectar uma instância: Bloc.observer = AppBlocObserver(), e todo o rastreamento de estado da aplicação fica disponível centralizadamente.
BlocProvider — um InheritedWidget do flutter_bloc que fornece um Bloc aos widgets filhos. Quando um widget é inicializado, BlocProvider cria um Bloc, e quando destruído — fecha automaticamente via close(). BlocProvider pode ser colocado no nível do MaterialApp (Bloc global) ou no nível de uma rota específica (Bloc local).
BlocProvider(
create: (context) => CounterBloc(),
child: Column(
children: [
BlocBuilder<CounterBloc, int>(
builder: (context, state) => Text('$state'),
),
ElevatedButton(
onPressed: () => context.read<CounterBloc>().add(Increment()),
child: Text('+'),
),
],
),
)BlocBuilder — um widget que reconstrói a UI a cada novo State. BlocListener — para efeitos colaterais (processar um State uma vez, sem reconstruir a UI): mostrar um SnackBar, navegar para outra tela. BlocConsumer — uma combinação de Builder e Listener para casos onde são necessários tanto reconstrução quanto efeito colateral. BlocSelector — para reconstrução seletiva apenas quando um campo específico do State muda.
MultiBlocProvider — um widget para BlocProviders aninhados sem aumentar níveis de aninhamento. Uma aplicação Flutter com 10-15 Blocs usa MultiBlocProvider no nível raiz para registrar todos os Blocs disponíveis para toda a aplicação: AuthenticationBloc, CartBloc, SettingsBloc.
BLoC é testado isoladamente sem widgets Flutter. Basta importar o pacote Dart flutter_test e o pacote bloc_test. O cenário de teste: criar um Bloc, adicionar um Event, verificar o State. blocTest — um utilitário que automatiza a sequência: build → act → expect.
blocTest<CounterBloc, int>(
'emits [1] when Increment is added',
build: () => CounterBloc(),
act: (bloc) => bloc.add(Increment()),
expect: () => [1],
)Mocking: Um Bloc que depende de um repositório ou API é testado com mocks via mocktail. O repositório é simulado no nível de abstração, e o Bloc recebe as dependências simuladas através do construtor. Hydrated Bloc — uma extensão para persistência/restauração automática de estado em armazenamento local. É testado com HydratedBlocStorage e armazenamento de arquivo temporário.
Pastas e arquivos: uma estrutura típica de projeto Flutter com BLoC: bloc/counter_bloc.dart, bloc/counter_event.dart, bloc/counter_state.dart. Para 30+ telas, recomenda-se agrupamento por funcionalidades: features/auth/bloc/, features/cart/bloc/. Cada Bloc é um arquivo separado, cada Event e State — seja em arquivos separados ou em um arquivo com o Bloc.
Desempenho: BLoC não cria sobrecarga para Streams vazios. BlocBuilder usa buildWhen para filtrar reconstruções — o widget só atualiza quando uma condição específica muda. Close garante que Blocs inativos não consumam memória. De acordo com Flutter DevTools, BLoC adiciona menos de 1% ao tamanho do bundle.
Migração do Provider: BLoC coexiste facilmente com Provider no mesmo projeto. Migração gradual: primeiro substitua os Providers mais complexos por Bloc, depois o restante. BlocProvider é compatível com a árvore Provider: widgets antigos podem usar Provider, novos — BlocProvider, dentro de uma única aplicação.
Perguntas frequentes
BLoC usa Event + Stream para isolamento da lógica de negócio e tipagem forte. Provider é um wrapper em torno de InheritedWidget para injeção simples de dependência e ChangeNotifier. BLoC é melhor para cenários complexos com múltiplos estados, Provider — para estado de UI local. BLoC requer mais boilerplate, mas fornece rastreabilidade completa através de Events.
Hydrated Bloc é uma extensão do pacote hydrated_bloc que salva automaticamente o último State no armazenamento local (Hive por padrão). Quando a aplicação reinicia, o Bloc restaura o estado salvo em vez do inicial. Isso resolve o problema de persistência sem chamadas manuais de salvamento: login, carrinho, configurações são salvos automaticamente entre sessões.
Um erro no BLoC é tratado através de try-catch dentro de mapEventToState ou on<Event>. Em caso de erro, Bloc retorna um State de erro: yield LoadError(error.message). Na UI, BlocListener ou BlocConsumer verifica o State pelo tipo de erro e mostra um SnackBar ou diálogo. BlocObserver registra globalmente todas as exceções não tratadas.
BLoC é um padrão específico do Flutter, pois usa Dart Stream e widgets Flutter. O conceito Event → Bloc → State pode ser adaptado para AngularDart e Server-side Dart, mas o ecossistema principal (BlocProvider, BlocBuilder, BlocObserver) está vinculado ao Flutter. Para React Native, use Redux ou MobX; para SwiftUI, use Combine + MVVM.
Cubit — para estados simples (contador, toggle, formulário com 2-3 campos). Bloc — para lógica complexa (feed de notícias, processamento de pedidos, autorização). A regra principal: se você precisa de rastreamento de cada ação (Event) para análise ou depuração — escolha Bloc. Se métodos que mudam o estado são suficientes — escolha Cubit. Ambos os padrões podem coexistir no mesmo projeto.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também