Answer
Overview
BLoC (Business Logic Component) is a design pattern where UI events flow into the BLoC, business logic runs, and new states flow back to the UI — in a strictly unidirectional data flow.
BLoC Data Flow
textUI Widget │ dispatch Event (e.g., LoginButtonPressed) ▼ Bloc.add(event) │ mapEventToState / on<Event>() handler ▼ Business Logic (API calls, validation, transformations) │ emit(newState) ▼ State (e.g., LoginLoading, LoginSuccess, LoginFailure) │ BlocBuilder / BlocListener listens ▼ UI Widget rebuilds
Complete BLoC Example — Login
1. Events (User Actions)
dartabstract class LoginEvent {} class LoginSubmitted extends LoginEvent { final String email; final String password; LoginSubmitted({required this.email, required this.password}); } class LogoutRequested extends LoginEvent {}
2. States (UI States)
dartabstract class LoginState {} class LoginInitial extends LoginState {} class LoginLoading extends LoginState {} class LoginSuccess extends LoginState { final User user; LoginSuccess(this.user); } class LoginFailure extends LoginState { final String error; LoginFailure(this.error); }
3. BLoC (Business Logic)
dartimport 'package:flutter_bloc/flutter_bloc.dart'; class LoginBloc extends Bloc<LoginEvent, LoginState> { final AuthRepository _authRepo; LoginBloc(this._authRepo) : super(LoginInitial()) { on<LoginSubmitted>(_onLoginSubmitted); on<LogoutRequested>(_onLogoutRequested); } Future<void> _onLoginSubmitted( LoginSubmitted event, Emitter<LoginState> emit, ) async { emit(LoginLoading()); try { final user = await _authRepo.signIn(event.email, event.password); emit(LoginSuccess(user)); } catch (error) { emit(LoginFailure(error.toString())); } } void _onLogoutRequested(LogoutRequested event, Emitter<LoginState> emit) { _authRepo.signOut(); emit(LoginInitial()); } }
4. Provide BLoC
dartBlocProvider( create: (context) => LoginBloc(AuthRepository()), child: LoginScreen(), )
5. UI — Consume BLoC
dartclass LoginScreen extends StatelessWidget { Widget build(BuildContext context) { return BlocListener<LoginBloc, LoginState>( listener: (context, state) { // Side effects (navigation, snackbar) if (state is LoginSuccess) { Navigator.pushReplacementNamed(context, '/home'); } if (state is LoginFailure) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(state.error)), ); } }, child: BlocBuilder<LoginBloc, LoginState>( builder: (context, state) { if (state is LoginLoading) return CircularProgressIndicator(); return Column( children: [ EmailField(), PasswordField(), ElevatedButton( onPressed: () { context.read<LoginBloc>().add( LoginSubmitted(email: _email, password: _password), ); }, child: Text('Login'), ), ], ); }, ), ); } }
BLoC Widgets Summary
| Widget | Purpose |
|---|---|
text | Create and provide BLoC |
text | Rebuild UI on state change |
text | Side effects (navigation, snackbar) |
text | Both Builder + Listener in one |
text | Provide multiple BLoCs |
text | Get BLoC without listening |
text | Get BLoC and rebuild on change |
Key Principle: Events go IN → Business Logic runs → States come OUT. The UI never modifies state directly — it only dispatches events.