๐Ÿง  What is BLoC?

BLoC is an architectural pattern that helps separate your appโ€™s business logic (data processing, state changes) from the UI.
It uses Streams and Events to handle data and state reactively.


๐Ÿงฉ Step 1: Create a New Flutter Project

In your terminal:

flutter create bloc_example
cd bloc_example

โš™๏ธ Step 2: Add Dependencies

In your pubspec.yaml, add:

dependencies:
  flutter:
    sdk: flutter
  flutter_bloc: ^8.1.3   # check for latest version

Then run:

flutter pub get

๐Ÿงฑ Step 3: Understand the BLoC Structure

A typical BLoC setup has 3 parts:

  1. Event โ†’ What happened (e.g., button pressed)
  2. State โ†’ What should the UI look like
  3. Bloc โ†’ Converts events into states

Example folder structure:

lib/
 โ”œโ”€โ”€ bloc/
 โ”‚    โ”œโ”€โ”€ counter_bloc.dart
 โ”‚    โ”œโ”€โ”€ counter_event.dart
 โ”‚    โ””โ”€โ”€ counter_state.dart
 โ””โ”€โ”€ main.dart

๐Ÿช„ Step 4: Create the Counter Event

lib/bloc/counter_event.dart

import 'package:equatable/equatable.dart';

abstract class CounterEvent extends Equatable {
  const CounterEvent();

  @override
  List<Object> get props => [];
}

class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}

๐Ÿงพ Step 5: Create the Counter State

lib/bloc/counter_state.dart

import 'package:equatable/equatable.dart';

class CounterState extends Equatable {
  final int counterValue;

  const CounterState(this.counterValue);

  @override
  List<Object> get props => [counterValue];
}

โš™๏ธ Step 6: Create the Counter BLoC

lib/bloc/counter_bloc.dart

import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_event.dart';
import 'counter_state.dart';

class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(const CounterState(0)) {
    on<Increment>((event, emit) {
      emit(CounterState(state.counterValue + 1));
    });

    on<Decrement>((event, emit) {
      emit(CounterState(state.counterValue - 1));
    });
  }
}

๐Ÿงฉ Step 7: Use BLoC in the UI

lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'bloc/counter_bloc.dart';
import 'bloc/counter_event.dart';
import 'bloc/counter_state.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocProvider(
        create: (_) => CounterBloc(),
        child: const CounterPage(),
      ),
    );
  }
}

class CounterPage extends StatelessWidget {
  const CounterPage({super.key});

  @override
  Widget build(BuildContext context) {
    final counterBloc = context.read<CounterBloc>();

    return Scaffold(
      appBar: AppBar(title: const Text('BLoC Counter Example')),
      body: Center(
        child: BlocBuilder<CounterBloc, CounterState>(
          builder: (context, state) {
            return Text(
              'Counter Value: ${state.counterValue}',
              style: const TextStyle(fontSize: 24),
            );
          },
        ),
      ),
      floatingActionButton: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            heroTag: 'decrement',
            onPressed: () => counterBloc.add(Decrement()),
            child: const Icon(Icons.remove),
          ),
          const SizedBox(width: 10),
          FloatingActionButton(
            heroTag: 'increment',
            onPressed: () => counterBloc.add(Increment()),
            child: const Icon(Icons.add),
          ),
        ],
      ),
    );
  }
}

๐Ÿง  Step 8: Run Your App

Run:

flutter run

Youโ€™ll see a simple counter app that increments and decrements using BLoC logic!


๐ŸŽฏ Optional Improvements

  • Add BlocListener to show snackbars or dialogs when state changes.
  • Use MultiBlocProvider if you have multiple blocs.
  • Use HydratedBloc to persist states.