FlutterBloc - Simplify State Management with Flutter Bloc Pattern

A portrait painting style image of a pirate holding an iPhone.

by The Captain

on
July 20, 2023
FlutterBloc - Simplify State Management with Flutter Bloc Pattern

FlutterBloc - Simplify State Management with Flutter Bloc Pattern

The FlutterBloc package is a state management solution that utilizes the Bloc pattern, which stands for Business Logic Component. It provides a structured and predictable way to manage the application state by separating the business logic from the UI layer.

Bloc pattern works on the principle of streams and sinks. It allows for the creation of event streams that the UI components can react to, and the business logic can respond with states. This decoupling of events and states makes it easier to test and maintain the codebase.

To use the FlutterBloc package, first, you need to include it in your project's dependencies in the pubspec.yaml file:

dependencies:
  flutter_bloc: ^7.0.0

Next, you can define your bloc by extending the Bloc class provided by the package. Let's take an example of a simple counter application to understand the basic usage:

import 'package:flutter_bloc/flutter_bloc.dart';

enum CounterEvent {
  increment,
  decrement,
}

class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0);

  @override
  Stream<int> mapEventToState(CounterEvent event) async* {
    switch (event) {
      case CounterEvent.increment:
        yield state + 1;
        break;
      case CounterEvent.decrement:
        yield state - 1;
        break;
    }
  }
}

In this example, we define a CounterBloc class that extends Bloc and takes an event type of CounterEvent and a state type of int. The initial state is set to 0.

The mapEventToState method is overridden to handle the different events and yield the corresponding states based on the event. The yield keyword is used to emit new states to the UI component subscribed to this bloc.

To utilize this bloc in a Flutter widget, you can wrap it with the BlocProvider widget:

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider<CounterBloc>(
      create: (context) => CounterBloc(),
      child: CounterView(),
    );
  }
}

Now, in the CounterView widget, you can access the bloc using the BlocProvider.of<CounterBloc>(context) method:

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

    return Scaffold(
      appBar: AppBar(title: Text('Counter')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                counterBloc.add(CounterEvent.decrement);
              },
              child: Icon(Icons.remove),
            ),
            SizedBox(width: 10),
            BlocBuilder<CounterBloc, int>(
              builder: (context, count) {
                return Text(
                  '$count',
                  style: TextStyle(fontSize: 32),
                );
              },
            ),
            SizedBox(width: 10),
            ElevatedButton(
              onPressed: () {
                counterBloc.add(CounterEvent.increment);
              },
              child: Icon(Icons.add),
            ),
          ],
        ),
      ),
    );
  }
}

In this widget, we use the BlocBuilder widget provided by flutter_bloc package to rebuild the UI whenever the state changes. It takes the bloc and a builder function that provides the latest state.

By following this pattern with the FlutterBloc package, you can simplify the state management in your Flutter applications and organize your codebase in a more scalable and maintainable way.

Subject: FlutterBloc