Unlocking Cubit: Simplifying State Management in Flutter

Raphael Pontes
5 min readMay 3, 2024

--

Developing applications for mobile devices is an exciting journey, Flutter is a framework created by Google, here to simplify this journey. But there is one concept that may seem challenging to beginners: state management. In this article, we’ll explore why state management is crucial and how Cubit can make this task easier.

What is Flutter and State Management:

Flutter is an open source framework that enables the development of native mobile apps for iOS and Android from a single codebase. It uses the Dart language and offers a modern, responsive approach to creating beautiful, fluid user interfaces.

State management is critical in any application because it allows you to dynamically control and update data and the user interface in response to events and user interactions. In the context of Flutter, where user interfaces are highly dynamic, state management becomes even more important to ensure application consistency.

Benefits of State Management in Flutter and Cubit:

Effectively using state management brings several benefits, including:

  1. Code Organization: Clear separation between business logic and user interface, facilitating code maintenance and scalability.
  2. Bug Prevention: Reduction of bugs related to incorrect manipulation of states and data.
  3. Improved User Experience: More dynamic user interfaces, providing a more pleasant user experience.

Cubit, a state management library for Flutter, offers a simplified and efficient approach to handling application state. It makes it easy to separate business rules pages and provides a clear, responsive data flow between application components.

Exploring Cubit:

Cubit is a powerful tool for state management in Flutter. Let’s take a closer look at some of its main classes and functions:

  • BlocProvider: This class plays a key role in providing Cubit to the widget tree. It is placed at the top of the widget hierarchy and allows any descendant widgets to access Cubit. This is done through the BlocProvider.of<T>(context) method, where T is the type of Cubit being accessed. This approach makes dependency injection easier and ensures that all widgets that need to access Cubit can do so easily.
  • Cubit: The Cubit class is the heart of the state management system. It extends the Cubit<T> class, where T is the type of state being managed. Cubit has methods for updating the state and notifying interested widgets about changes. The emit(T state) method is used to emit a new state, while the addError and onError methods are used to handle errors that may occur during application execution. The close() method is used to free up resources when Cubit is no longer needed.
  • BlocBuilder: This widget is a convenient way to rebuild child widgets whenever the Cubit state changes. It takes the Cubit type and state type as generic parameters and a widget constructor that is called whenever the Cubit state changes. This ensures that the user interface updates efficiently and responsively whenever there is a change in state.

Installing the Cubit:

Before we start using Cubit in our Flutter projects, we need to install it in our development environment. Fortunately, this is quite simple thanks to the Dart package manager, Pub.
Just run this command in your terminal within the Flutter project.

flutter pub add flutter_bloc

Or add the dependency to your pubspec.yaml file: Open your Flutter project’s pubspec.yaml file and add the following line under the dependencies section:

dependencies:
flutter:
sdk: flutter
flutter_bloc:

This tells Dart Pub to download and install the Flutter Bloc library (which includes Cubit) in its latest version compatible with the specified version.
After saving the pubspec.yaml file, open a terminal in the root of your Flutter project and run the flutter pub get command. This will download and install the dependencies added to your project.
With these steps completed, Cubit is installed and ready to be used in your Flutter project.

Sample Code:

In the provided code example, we can see all these classes and functions in action. The Cubit is created and provided to the widget tree using the BlocProvider in the main.dart file. Then, on the CounterPage, the Cubit is accessed using BlocProvider.of<CounterCubit>(context), and the BlocBuilder is used to rebuild the widget whenever the Cubit’s state changes.

// main.dart
import 'package:cubit_example/counter_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

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

class MyApp extends StatelessWidget {
const MyApp({Key? key});

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Cubit Example',
theme: ThemeData(primarySwatch: Colors.blue),
home: BlocProvider(
create: (_) => CounterCubit(),
child: const CounterPage(),
),
);
}
}
// counter_cubit.dart
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);
}
// counter_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:cubit_example/counter_cubit.dart';

class CounterPage extends StatelessWidget {
const CounterPage({Key? key});

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

return Scaffold(
appBar: AppBar(
title: const Text('Counter Cubit Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('You have pushed the button this many times:'),
const SizedBox(height: 8),
BlocBuilder<CounterCubit, int>(
builder: (_, value) {
return Text(
'$value',
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
);
},
),
],
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: counterCubit!.increment,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
const SizedBox(height: 8),
FloatingActionButton(
onPressed: counterCubit.decrement,
tooltip: 'Decrement',
child: const Icon(Icons.remove),
),
],
),
);
}
}

Source code: https://github.com/rkpontes/flutter_cubit_example

To finish:

Mastering Cubit and state management in Flutter is essential for creating efficient, responsive mobile apps. Cubit simplifies this process by providing a clear, responsive approach to managing application state.
By exploring and understanding Cubit’s essential classes and functions, you will be well equipped to create powerful Flutter applications.
Remember to keep practicing, exploring the official Flutter documentation, and experimenting with different state management patterns and techniques.
With dedication and practice, you’ll be on your way to becoming a confident and experienced Flutter developer. So, get to work and keep learning and exploring the wonderful world of mobile app development with Flutter!

Important Links:

  1. Official Flutter Documentation
  2. Flutter Bloc Repository
  3. Flutter Community: The Flutter community is a great place to interact with other Flutter developers, ask questions, share experiences, and get support.
  4. Flutter Pub: is a Flutter package repository where you can find a wide variety of packages, including Flutter Bloc.
  5. Flutter Awesome: Flutter Awesome is a curated list of Flutter-related resources, tools, libraries, and examples. You can find a variety of useful resources here, including tutorials, videos, and popular libraries.
  6. Article in Portuguese

Did I help you? Buy me a coffee

Follow me in

--

--

Raphael Pontes
Raphael Pontes

Written by Raphael Pontes

Software Engineer - Mobile Developer - Expert Flutter Developer - Follow Me medium/instagram: @raphaelkennedy

Responses (1)