Flutter BLoC
01 / 02

flutter_bloc Fundamentals: Widgets & Access

flutter_bloc: Widgets & Access

flutter_bloc is the official Dart/Flutter package implementing the BLoC pattern -- providing the concrete Bloc, Cubit, BlocBuilder, BlocProvider, and BlocListener classes/widgets, rather than needing to hand-implement the underlying Stream plumbing. It's built on the framework-agnostic bloc package, adding Flutter's widget-tree integration on top.

The Core Widget Family

// Provides a Bloc/Cubit instance to the widget tree
BlocProvider(
  create: (context) => LoginBloc(context.read<AuthRepository>()),
  child: LoginScreen(),
)

// Rebuilds UI in response to state changes
BlocBuilder<LoginBloc, LoginState>(
  builder: (context, state) {
    if (state is LoginLoading) return CircularProgressIndicator();
    return LoginForm();
  },
)

// Side effects (navigation, snackbars) WITHOUT rebuilding UI
BlocListener<LoginBloc, LoginState>(
  listener: (context, state) {
    if (state is LoginSuccess) Navigator.pushNamed(context, '/home');
  },
  child: LoginForm(),
)

// Combines Builder + Listener in one widget -- avoids nesting them
BlocConsumer<LoginBloc, LoginState>(
  listener: (context, state) {
    if (state is LoginSuccess) Navigator.pushNamed(context, '/home');
  },
  builder: (context, state) {
    return state is LoginLoading ? CircularProgressIndicator() : LoginForm();
  },
)

Dispatching Events with read()

// Looks up the nearest ancestor BlocProvider<T> -- no manual
// prop-drilling through intermediate widget constructors
ElevatedButton(
  onPressed: () => context.read<LoginBloc>().add(LoginSubmitted(email, password)),
  child: Text('Log in'),
)

MultiBlocProvider & RepositoryProvider

// Avoids deeply nested provider widgets
MultiBlocProvider(
  providers: [
    BlocProvider(create: (_) => AuthBloc()),
    BlocProvider(create: (_) => CartBloc()),
  ],
  child: MyApp(),
)

// RepositoryProvider: plain dependency injection, distinct from
// Bloc/Cubit state management -- a Bloc then consumes it
RepositoryProvider(
  create: (_) => AuthRepository(),
  child: BlocProvider(
    create: (context) => LoginBloc(context.read<AuthRepository>()),
    child: LoginScreen(),
  ),
)

Initial State

// The state a widget sees before any event has been processed
class LoginBloc extends Bloc<LoginEvent, LoginState> {
  LoginBloc(this.authRepository) : super(LoginInitial()) {
    on<LoginSubmitted>((event, emit) async { /* ... */ });
  }
}

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free