Skip to main content

Bloc

  • Propriedade **listener**

    • Quando você fornece um listener, ele será acionado sempre que ocorrer uma mudança no estado do bloco associado.
    BlocProvider(
    create: (context) => MeuBloc(),
    listener: (context, state) {
    // Atualize a interface do usuário ou execute outras ações com base no novo estado
    if (state is MeuEstado) {
    // Faça algo
    } else if (state is OutroEstado) {
    // Faça outra coisa
    }
    },
    child: MeuWidget(),
    )

    .Value

    • Quando você já criou um bloc em um diferente BlocProvider e você só quer isso mesmo bloco para estar disponível em outro lugar na árvore de widgets.

      BlocProvider.value(
      value: BlocProvider.of<BlocA>(context),
      child: ScreenA(),
      );
  • Propriedade **builder**

    • O builder é uma função de retorno de chamada que é chamada sempre que ocorrer uma mudança no estado do bloco associado. Ela é responsável por construir a UI com base no novo estado.
  • Propriedade **child**

    • O widget filho é aquele que será construído de forma estática e não será reconstruído quando ocorrerem alterações no estado do bloco.
  • quando se trabalha com blocprovider ou multiblocprovider, eles já dão o dispose, mas é uma boa prática usar o método close

    @override
    Future<void> close() async {
    _emailController.close();
    _passwordController.close();
    return super.close();
    }

    Do I need to dispose cubit instances?

Explicação sobre as funções

1. Eventos e Estados

  • Evento: Representa ações ou intenções do usuário ou do sistema que são enviadas para o BLoC.

    abstract class CounterEvent {}
    class Increment extends CounterEvent {}
    class Decrement extends CounterEvent {}
  • Estado: Representa a condição atual da interface de usuário, modificada de acordo com os eventos processados pelo BLoC.

    abstract class CounterState {}
    class CounterValue extends CounterState {
    final int value;
    CounterValue(this.value);
    }

2. BLoC (Business Logic Component)

  • Criar BLoC: Herda de Bloc<Event, State>, onde você define o comportamento ao receber um evento e emitir o novo estado.

    class CounterBloc extends Bloc<CounterEvent, CounterState> {
    CounterBloc() : super(CounterValue(0)) {
    on<Increment>((event, emit) => emit(CounterValue(state.value + 1)));
    on<Decrement>((event, emit) => emit(CounterValue(state.value - 1)));
    }
    }
  • on<Event>: Escuta um evento específico e executa uma ação (função) que altera o estado.

    on<EventName>((event, emit) => /* Lógica do evento */);

3. Streams no BLoC

  • Stream de estados: Emite os novos estados da aplicação para serem observados pela UI.

    Stream<CounterState> get stream => _stateController.stream;
  • Adicionar eventos: Adiciona novos eventos ao BLoC para serem processados.

    counterBloc.add(Increment());
  • Emitir estados: Emite novos estados a partir da lógica de negócios.

    emit(CounterValue(state.value + 1));

4. BlocProvider (Gerenciamento de Injeção de Dependência)

  • Fornecer BLoC: O BlocProvider fornece o BLoC para a árvore de widgets.

    BlocProvider(
    create: (context) => CounterBloc(),
    child: MyApp(),
    );
  • Recuperar BLoC: Obtém uma instância do BLoC de qualquer parte da árvore de widgets.

    final bloc = BlocProvider.of<CounterBloc>(context);

5. BlocBuilder (Construir UI com base no estado)

  • Constrói a interface de usuário baseada no estado atual emitido pelo BLoC.
    BlocBuilder<CounterBloc, CounterState>(
    builder: (context, state) {
    if (state is CounterValue) {
    return Text('Valor: ${state.value}');
    }
    return CircularProgressIndicator();
    },
    );

6. BlocListener (Escutar mudanças de estado para ações únicas)

  • Executa ações com base nas mudanças de estado, sem reconstruir a interface.
    BlocListener<CounterBloc, CounterState>(
    listener: (context, state) {
    if (state is CounterValue && state.value == 10) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Valor chegou a 10!")));
    }
    },
    child: MyWidget(),
    );

7. BlocConsumer (Combinação de Builder e Listener)

  • Combina BlocBuilder e BlocListener, permitindo construir a interface e realizar ações baseadas no estado.
    BlocConsumer<CounterBloc, CounterState>(
    listener: (context, state) {
    // Ação com base no estado
    },
    builder: (context, state) {
    // Construção da interface de usuário
    },
    );

8. BlocObserver (Monitoramento global de eventos e transições)

  • Usado para observar todas as transições e eventos globalmente.

    class AppBlocObserver extends BlocObserver {

    void onTransition(Bloc bloc, Transition transition) {
    print(transition);
    super.onTransition(bloc, transition);
    }
    }
  • Definir o Observer: Adicione o BlocObserver no início da aplicação.

    void main() {
    Bloc.observer = AppBlocObserver();
    runApp(MyApp());
    }

9. MultiBlocProvider (Múltiplos BLoCs)

  • Fornece múltiplos BLoCs ao mesmo tempo para a árvore de widgets.
    MultiBlocProvider(
    providers: [
    BlocProvider(create: (context) => CounterBloc()),
    BlocProvider(create: (context) => AnotherBloc()),
    ],
    child: MyApp(),
    );

Funções chave de cada elemento:

  • add(Event): Adiciona um evento para ser processado.
  • emit(State): Emite um novo estado.
  • on<Event>((event, emit)): Define a lógica para processar um evento e emitir um estado.
  • BlocBuilder: Constrói a UI com base no estado atual.
  • BlocListener: Escuta mudanças de estado para executar ações (sem reconstruir a UI).
  • BlocConsumer: Combina BlocBuilder e BlocListener.
  • BlocProvider: Fornece o BLoC para a árvore de widgets.
  • BlocObserver: Monitora globalmente transições e eventos.

Fluxo

Usuário Interage com a UI
⬇️
Um Evento é Disparado ➡️ **add(Event)**
⬇️
BLoC recebe o Evento ➡️ **on<Event>()**
⬇️
BLoC Processa o Evento e Lógica de Negócio ➡️ **emit(State)**
⬇️
Novo Estado é Emitido ➡️ **emit(State)**
⬇️
UI Escuta o Novo Estado (via BlocBuilder ou BlocListener) ➡️ **BlocBuilder** ou **BlocListener**
⬇️
UI é Atualizada com base no Novo Estado

Descrição detalhada com as funções correspondentes:

  1. Usuário Interage com a UI: O usuário realiza uma ação, como clicar em um botão ou digitar em um campo de texto.

  2. Um Evento é Disparado ➡️ add(Event):

    • A interação do usuário dispara um evento, que é enviado ao BLoC com o método add(Event).
    • Exemplo: bloc.add(Increment());
  3. BLoC recebe o Evento ➡️ on<Event>():

    • O BLoC detecta o evento e, dentro da função on<Event>(), processa esse evento. Essa função define o que acontece quando o evento é recebido.
    • Exemplo:
      on<Increment>((event, emit) {
      emit(CounterState(state.value + 1));
      });
  4. BLoC Processa o Evento e Lógica de Negócio ➡️ emit(State):

    • A lógica de negócios é processada dentro da função on<Event>(). Com base nessa lógica, o BLoC cria um novo estado.
    • Exemplo:
      emit(CounterState(state.value + 1)); // Novo estado emitido
  5. Novo Estado é Emitido ➡️ emit(State):

    • O BLoC emite o novo estado com o método emit(State), informando que algo mudou no estado da aplicação.
    • Exemplo:
      emit(CounterState(state.value + 1)); // Emissão do novo estado
  6. UI Escuta o Novo Estado ➡️ BlocBuilder ou BlocListener:

    • A UI está escutando as mudanças no estado usando um BlocBuilder ou BlocListener. Sempre que o estado mudar, a UI será notificada e pode reagir a essa mudança.
    • Exemplo de uso com BlocBuilder:
      BlocBuilder<CounterBloc, CounterState>(
      builder: (context, state) {
      return Text('Valor atual: ${state.value}');
      },
      );
  7. UI é Atualizada com base no Novo Estado:

    • A interface é automaticamente atualizada com base no novo estado. O BlocBuilder ou BlocListener executa a atualização da UI, mostrando, por exemplo, um novo valor no contador ou uma lista de dados atualizada.

BlocBuilder X BlocConsumer

🧱 1. BlocBuilder

👉 Para construir a interface (UI) com base no estado do bloc/cubit.

Ele ouve mudanças de estado e reconstrói o widget quando o estado muda.

📌 Exemplo:

BlocBuilder<ServicoCubit, ServicoState>(
builder: (context, state) {
if (state is ServicoCarregando) {
return CircularProgressIndicator();
} else if (state is ServicoCarregado) {
return ListView(...);
} else {
return Text('Erro');
}
},
)

Quando usar:

  • Para mostrar diferentes partes da UI de acordo com o estado.
  • Ideal quando só quer reagir visualmente à mudança de estado.

🎧 2. BlocConsumer

👉 Combina o BlocBuilder e o BlocListener.

Você usa quando precisa:

  • Construir UI com base no estado (builder)
  • Executar efeitos colaterais (snackbar, dialog, navegação) com o listener

📌 Exemplo:

BlocConsumer<ServicoCubit, ServicoState>(
listener: (context, state) {
if (state is ServicoErro) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Erro: ${state.message}')),
);
}
},
builder: (context, state) {
if (state is ServicoCarregado) {
return ListView(...);
} else {
return CircularProgressIndicator();
}
},
)

Quando usar:

  • Quando você precisa mostrar mensagens de feedback, navegar, mostrar modal, etc, sem reconstruir a UI.
  • Evita que essas ações (como mostrar SnackBar) aconteçam dentro do builder, o que é errado no Flutter.

🤓 Resumo rápido:

ComponenteServe para...Recomendações
BlocBuilderReconstruir UI com base no estadoUse quando só precisa exibir dados na tela
BlocConsumerReconstruir UI + ouvir estado para açõesUse quando precisa reagir e construir a UI
BlocListenerOuvir o estado para ações (sem UI)Use junto com widgets onde não precisa reconstruir