Flutter State Management: Bloc vs. setState — A Comparative Analysis

shivraj
5 min readSep 29, 2023

--

Management

In this article, we will explore the appropriate use cases for setState and BLoC (Business Logic Component) in Flutter state management. We'll examine when to use each approach and the potential challenges they address.

It’s not a good idea to get caught taking ice cream from the fridge by shouting when your parents are sleeping, just as it’s not efficient to rebuild all the widgets underneath a specific one when you can use a state management pattern like BLoC.

In the first diagram, which represents a widget tree, we can see that using setState at a particular widget, such as the "Row" widget, causes all of its ancestor widgets to be rebuilt. This can be inefficient, especially when dealing with nested containers or complex widget trees. Unnecessary rebuilding can lead to performance issues.

Now, let’s delve into how BLoC works:

With BLoC, you can manage the state of your application in a more efficient and organized manner. Let’s say you have a variable that is only used within the “Row” widget. When you use BLoC, you can update the state of this specific variable without triggering the rebuilding of all the widgets above it in the hierarchy.

This approach becomes particularly valuable in larger enterprise-level applications. In such cases, performance optimization is crucial, and using BLoC or a similar state management solution becomes essential. By doing so, you ensure that your app remains responsive and efficient, even as its complexity grows.

let’s discuss how BLoC works using an example of incrementing a variable. In BLoC-based implementations, you typically have three essential components:

  1. Main BLoC: This is where changes to your variable occur. It acts as a central hub for managing state and logic.
  2. BLoC State: States represent different conditions or values of your variable. Every event should correspond to a state. States are used to reflect changes in your variable and its associated data.
  3. BLoC Events: Events are actions or triggers that lead to changes in your variable’s state. Events are typically associated with user interactions or other external factors that affect your variable.

To increment a variable, we can create an event called IncrementEvent, which signifies the intention to increase the variable's value. Additionally, we need to define a state called UpdateState to represent the new value of the variable after it's been incremented. Here's how we can structure our

//main bloc
import 'package:bloc_project/variable_event.dart';
import 'package:bloc_project/variable_state.dart';
import 'package:bloc/bloc.dart';

class CounterBloc extends Bloc<IncrementEvent,UpdateState > {
CounterBloc() : super(const UpdateState()) {

on<VariableUpdateEvent>((event, emit) {
emit(VariableUpdateState(x :event.x!+1));
});
}
}
//event class

class IncrementEvent {
const IncrementEvent();
}
class VariableUpdateEvent extends IncrementEvent {
final int? x;
const VariableUpdateEvent(this.x);
}
//state class

class UpdateState {
const UpdateState();
}
class VariableUpdateState extends UpdateState {
final int? x;
const VariableUpdateState({this.x});
}
//UI

class MyHomePage extends StatelessWidget {
MyHomePage({super.key, required this.title});

final String title;

int _counter = 0;

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

variableMainBloc() {
return BlocListener<CounterBloc, UpdateState>(
listener: (context, state) {},
child: BlocBuilder<CounterBloc, UpdateState>(
builder: (context, state) {
if (state is VariableUpdateState) {
_counter = state.x!;
return bodyLoader(context);
}
return bodyLoader(context);
},
),
);
}

Widget bodyLoader(context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(title),
),
body: Center(
child: Column(
children: [
Container(
color: Colors.green,
padding:const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
child: InkWell(
onTap: () {
BlocProvider.of<CounterBloc>(context)
.add(VariableUpdateEvent(_counter));
},
child: Text("click value is +$_counter"),
),
),
],
),
));
}
}

In this example:

  • IncrementEvent represents the intention to increment the variable.
  • UpdateState represents the new value of the variable after it's been incremented.
  • The CounterBloc handles the IncrementEvent and increments the variable. It then emits an UpdateState with the updated value.

Now, when you dispatch an IncrementEvent to the CounterBloc, it will increment the variable and emit an UpdateState, which can be observed by the UI to reflect the updated value.

In the above code we came across components like bloc create, bloc listener,bloc builder.hese components help you manage the state and behavior of your application.

Bloc Create (Bloc Initialization) :

  • This component refers to the initialization of your BLoC instances. In your application, you create instances of your BLoC classes to manage different parts of the application’s state and logic.
  • Typically, you create BLoC instances at the top level of your widget hierarchy, often within the main function or the build method of your app's root widget.

BlocBuilder :

  • BlocBuilder is a widget provided by the flutter_bloc package that rebuilds its child widget whenever the state of a specified Bloc changes.
  • It takes a Bloc and a builder function. The builder function receives the current Bloc state and returns a widget that depends on that state.
  • It’s used to efficiently update the UI in response to changes in the Bloc's state.

BlocListener :

  • BlocListener is another widget provided by the flutter_bloc package that listens to state changes in a Bloc but doesn't rebuild its child widget.
  • It’s useful for responding to state changes by executing side effects or performing actions in your UI.
  • It takes a Bloc and a listener function. The listener function is called whenever the Bloc's state changes.

Bloc Provider:

  • Bloc Provider is a widget that facilitates the creation and management of BLoCs.
  • It ensures that the same BLoC instance is provided consistently throughout the widget tree.
  • Bloc Provider is responsible for initializing BLoCs and making them accessible to parts of your application that need them.
  • This component helps centralize BLoC management, prevent memory leaks, and maintain a clean separation of concerns.

This is a basic example of how BLoC can be used to manage state and logic for incrementing a variable. BLoC helps maintain a clear separation between the UI and business logic, making it easier to manage complex state and events in your Flutter application.

Github repository

The code is open source, so if you want to get it you can do it here: https://github.com/shivrajbande/bloc_example.

Thanks for reading this article, I hope that now you could understand better how flutter bloc works and If this was helpful for you I’ll really appreciate your feedback and also your claps!👏

--

--