Effective state management with Flutter cubit

Pavithran
4 min readMay 21, 2023

--

Flutter has emerged as a popular framework for cross-platform mobile app development, offering developers a robust and expressive way to build beautiful and performant applications. One critical aspect of any Flutter app is state management, which ensures the efficient handling and synchronisation of data throughout the application. While there are various state management approaches available, one that stands out is the Flutter Cubit from BLoC pattern. In this article, we will explore the power and benefits of the Cubit and how it simplifies state management in Flutter.

Understanding Cubit:

Cubit is a state management solution built specifically for Flutter applications. It follows the principles of the BLoC (Business Logic Component) pattern and combines them with simplified semantics to provide a streamlined approach to state management.

“Cubit” represents a component responsible for managing a particular piece of state. It exposes methods to emit new states and can be consumed by UI components to react and render based on those states. The key idea behind Cubit is the unidirectional data flow, ensuring a predictable and maintainable state management process.

Benefits of Flutter Cubit:

  1. Simplicity and Clarity: Cubit promotes a clear separation of concerns, making it easier to understand and maintain code. By isolating the state management logic within Cubits, the UI components can focus solely on rendering the user interface based on the current state. This separation improves code organization, testability, and overall development efficiency.
  2. Predictable State Changes: With Cubit, state changes are explicitly triggered by emitting new states from Cubits. This approach enables a clear traceability of state changes and eliminates unexpected side effects. The unidirectional data flow ensures that state transitions occur in a controlled and predictable manner, making debugging and troubleshooting easier.
  3. Testability: Cubit promotes testability by separating business logic from the UI. Since Cubits encapsulate the state management logic, they can be easily tested in isolation using unit tests. This allows developers to thoroughly test different state scenarios and verify the behavior of the application without the need for complex UI interactions.
  4. Flexibility and Scalability: Cubit provides flexibility and scalability by allowing the composition of multiple Cubits to manage different parts of the application state. Each Cubit can focus on a specific feature or data domain, making it easier to reason about and extend the state management as the application grows. Additionally, Cubit integrates well with other Flutter libraries and frameworks, enabling seamless integration with existing codebases.

Implementing Cubit in Counter App:

First, you’ll need to add the flutter_bloc package to your pubspec.yaml file:

dependencies:
flutter:
sdk: flutter
flutter_bloc: ^7.3.0

We’ll implement cubit in CounterApp and get a glimpse of how it works. While starting we will use primitive types instead of our own custom state

Create a file counter_cubit.dart and add the following to it

import 'package:flutter_bloc/flutter_bloc.dart';

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

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

So in our cubit file, we have created a CounterCubit class that extends Cubit<int>. It manages the counter state and provides methods to increment and decrement the counter value.

and in the main.dart file update the below code

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

import 'counter_cubit.dart';

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

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Counter App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: BlocProvider(
create: (context) => CounterCubit(),
child: CounterPage(),
),
);
}
}

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

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

The CounterPage widget is wrapped with BlocProvider to provide the CounterCubit instance to the widget tree. Inside the CounterPage, we use the BlocBuilder widget from flutter_bloc to listen to state changes and rebuild the UI accordingly. The current counter value is displayed using a Text widget, and the increment and decrement buttons are implemented using FloatingActionButton widgets.

So, you’ll be having an app in hand with the UI with Add and subtract buttons where the onTap operations make the state to change using our cubit. Now the state of the app is managed by the Cubit.

I hope this code demonstration helps you understand how to implement a counter app using the Flutter Cubit. We’ll also try to implement the cubit with our own state in another article which is on the way. Happy Coding! 🙂

--

--

Pavithran

Machine learning enthusiast, App developer, web app developer.