Difference between BLoC and Cubit when using flutter_bloc package

By | December 22, 2023
Cubit Vs Bloc

Video Tutorial

Lets understand this with an example

we are going to create a basic counter example here using bloc and cubit.

Here are the key differences between Bloc and Cubit in Flutter:

  1. Complexity:
    • Bloc: Bloc is designed to handle more complex state management scenarios. It has support for handling events, side effects, and more advanced state transitions.
    • Cubit: Cubit is a more lightweight version of Bloc. It’s intended for simpler state management scenarios where you don’t need to handle events explicitly.
  2. Event Handling:
    • Bloc: Bloc has a dedicated on(Event...) method where you handle events and determine the new state based on those events.
    • Cubit: Cubit does not have a dedicated method for handling events. State changes are triggered directly using the emit method.
  3. Direct State Changes:
    • Bloc: State changes in Bloc are often indirect, happening in response to events.
    • Cubit: Cubit allows for more direct state changes using the emit method. You explicitly call emit to trigger state changes.
  4. Use Case:
    • Bloc: Use Bloc when your application involves complex state transitions, side effects, or when you need fine-grained control over event handling.
    • Cubit: Use Cubit for simpler scenarios where explicit event handling is not required, and you want a more straightforward way to manage state.
  5. Simplicity:
    • Bloc: Bloc provides more structure and features, but this can lead to more boilerplate code.
    • Cubit: Cubit is more concise and can be a good choice for scenarios where simplicity is a priority.
  6. Dependencies:
    • Bloc: Bloc relies on the bloc package.
    • Cubit: Cubit relies on the bloc package as well, but it is a subset of Bloc, providing a simpler API.
  7. Initialization:
    • Bloc: Bloc requires more setup with the mapEventToState method.
    • Cubit: Cubit is simpler to initialize and use.
  8. Preferred Use:
    • Bloc: Bloc is recommended for larger applications or scenarios where more advanced state management features are needed.
    • Cubit: Cubit is recommended for simpler applications or when a lightweight state management solution is sufficient.

Both Bloc and Cubit are part of the broader Flutter Bloc library and adhere to the principles of reactive programming. Your choice between Bloc and Cubit will depend on the specific requirements of your application and your preferences for simplicity versus feature richness.

Counter – Cubit Example

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

// Cubit
class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);

  void increment() => emit(state + 1);
  void decrement() => emit(state - 1);
}

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

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

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

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

  @override
  Widget build(BuildContext context) {
    final counterCubit = BlocProvider.of<CounterCubit>(context);

    return Scaffold(
      appBar: AppBar(
        title: const Text('Cubit Counter App'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('Counter Value:'),
            BlocBuilder<CounterCubit, int>(
              builder: (context, state) {
                return Text(
                  state.toString(),
                  style: const TextStyle(fontSize: 24),
                );
              },
            ),
          ],
        ),
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            onPressed: () {
              counterCubit.increment();
            },
            child: const Icon(Icons.add),
          ),
          const SizedBox(height: 16),
          FloatingActionButton(
            onPressed: () {
              counterCubit.decrement();
            },
            child: const Icon(Icons.remove),
          ),
        ],
      ),
    );
  }
}

Counter – Bloc Example

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

// Events
enum CounterEvent { increment, decrement }

// States
class CounterState {
  final int count;

  CounterState(this.count);
}

// Bloc
class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(CounterState(0)) {
    on<CounterEvent>((event, emit) {
      if (event == CounterEvent.increment) {
        emit(CounterState(state.count + 1));
      }
      if (event == CounterEvent.decrement) {
        emit(CounterState(state.count - 1));
      }
    });
  }
}

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

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

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

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

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

    return Scaffold(
      appBar: AppBar(
        title: const Text('Bloc Counter App'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('Counter Value:'),
            BlocBuilder<CounterBloc, CounterState>(
              builder: (context, state) {
                return Text(
                  state.count.toString(),
                  style: const TextStyle(fontSize: 24),
                );
              },
            ),
          ],
        ),
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            onPressed: () {
              counterBloc.add(CounterEvent.increment);
            },
            child: const Icon(Icons.add),
          ),
          const SizedBox(height: 16),
          FloatingActionButton(
            onPressed: () {
              counterBloc.add(CounterEvent.decrement);
            },
            child: const Icon(Icons.remove),
          ),
        ],
      ),
    );
  }
}

Explanation:

  1. Events and States:
    • CounterEvent is an enumeration representing events like increment and decrement.
    • CounterState represents the state of the counter, holding the current count.
  2. CounterBloc:
    • CounterBloc extends Bloc<CounterEvent, CounterState>.
    • The constructor initializes the Bloc with an initial state of CounterState(0).
    • on<CounterEvent> is used to define how the Bloc reacts to events. It emits a new state based on the event.
  3. MyApp:
    • The root widget of the application where BlocProvider is used to provide the CounterBloc to the widget tree.
  4. MyHomePage:
    • Displays the current count and has two floating action buttons to trigger increment and decrement events.
    • BlocBuilder listens to state changes and rebuilds the UI accordingly.

Differences between Bloc and Cubit:

  • This example uses Bloc for state management.
  • If using Cubit, you would change extends Bloc<CounterEvent, CounterState> to extends Cubit<CounterState>.
  • In this specific example, the difference between Bloc and Cubit might not be very apparent due to its simplicity. Bloc is generally chosen for more complex scenarios involving event handling and transitions. Cubit is preferred for simpler cases where direct state changes are sufficient.

Leave a Reply

Your email address will not be published. Required fields are marked *