Understanding BlocBuilder in Flutter: A Complete Guide

When it comes to managing state in Flutter applications, the BLoC (Business Logic Component) pattern stands out for its ability to separate business logic from UI code, promoting a clean and maintainable architecture. A crucial component of this pattern is the BlocBuilder widget, which rebuilds the UI in response to state changes. In this comprehensive guide, we’ll explore what BlocBuilder is, how it works, and how to use it effectively in your Flutter applications.

What is BlocBuilder?

BlocBuilder is a widget provided by the flutter_bloc package that listens to a Bloc or Cubit and rebuilds its child widget whenever the state changes. It allows you to build your UI based on the current state of your BLoC, making your app reactive and dynamic.

Why Use BlocBuilder?

  1. Reactivity: BlocBuilder ensures that your UI updates automatically in response to state changes, providing a smooth and interactive user experience.
  2. Separation of Concerns: It keeps your UI code separate from your business logic, promoting a cleaner and more maintainable codebase.
  3. Simplicity: BlocBuilder abstracts away the complexities of managing state changes, making it easier to implement and maintain.

How BlocBuilder Works

BlocBuilder takes two main parameters: the bloc (or cubit) it listens to and a builder function. The builder function is called whenever the state of the bloc changes, allowing you to rebuild the UI based on the new state.

Here’s a simple example to illustrate how BlocBuilder works:

Step 1: Add Dependencies

First, add the flutter_bloc package to your pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  flutter_bloc: ^8.0.0

Step 2: Define a Bloc

Let’s create a simple CounterBloc to manage the state of a counter:

import 'package:flutter_bloc/flutter_bloc.dart';

// Counter Event
abstract class CounterEvent {}

class Increment extends CounterEvent {}

class Decrement extends CounterEvent {}

// Counter State
class CounterState {
  final int counterValue;

  CounterState({required this.counterValue});
}

// Counter Bloc
class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(CounterState(counterValue: 0));

  @override
  Stream<CounterState> mapEventToState(CounterEvent event) async* {
    if (event is Increment) {
      yield CounterState(counterValue: state.counterValue + 1);
    } else if (event is Decrement) {
      yield CounterState(counterValue: state.counterValue - 1);
    }
  }
}

Step 3: Use BlocBuilder in the UI

Now, let’s use BlocBuilder to build our UI based on the state of CounterBloc:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocProvider(
        create: (context) => CounterBloc(),
        child: CounterScreen(),
      ),
    );
  }
}

class CounterScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Flutter BlocBuilder Example')),
      body: Center(
        child: BlocBuilder<CounterBloc, CounterState>(
          builder: (context, state) {
            return Text(
              'Counter Value: ${state.counterValue}',
              style: TextStyle(fontSize: 24.0),
            );
          },
        ),
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            onPressed: () => context.read<CounterBloc>().add(Increment()),
            child: Icon(Icons.add),
          ),
          SizedBox(height: 10),
          FloatingActionButton(
            onPressed: () => context.read<CounterBloc>().add(Decrement()),
            child: Icon(Icons.remove),
          ),
        ],
      ),
    );
  }
}

Advanced Usage of BlocBuilder

BlocBuilder also provides additional functionality for more advanced use cases:

  1. Build When: You can use the buildWhen parameter to control when the builder function is called. This is useful if you want to avoid unnecessary rebuilds.
BlocBuilder<CounterBloc, CounterState>(
  buildWhen: (previous, current) {
    // Rebuild only if the counter value is even
    return current.counterValue % 2 == 0;
  },
  builder: (context, state) {
    return Text(
      'Counter Value: ${state.counterValue}',
      style: TextStyle(fontSize: 24.0),
    );
  },
);

2. Multiple BlocBuilders: You can use multiple BlocBuilder widgets in your UI to listen to different blocs or to build different parts of your UI based on different states.

BlocBuilder<CounterBloc, CounterState>(
  builder: (context, counterState) {
    return BlocBuilder<AnotherBloc, AnotherState>(
      builder: (context, anotherState) {
        // Build UI based on both counterState and anotherState
      },
    );
  },
);

Conclusion

BlocBuilder is an essential widget in the Flutter BLoC ecosystem, providing a straightforward way to rebuild your UI in response to state changes. By using BlocBuilder, you can ensure that your Flutter applications remain reactive, maintainable, and scalable.

Whether you’re building a simple app or a complex enterprise application, understanding and leveraging the power of BlocBuilder will help you manage state effectively and keep your codebase clean and organized.

Happy coding!


By mastering BlocBuilder, you can create highly responsive and dynamic UIs in your Flutter applications. For more in-depth information, consider exploring the official BLoC documentation and other related resources.

Leave a Comment