Top five Flutter state management in 2023 Part 1

Chandrakant Vemula
Canadiv’s Technology and Design
4 min readDec 15, 2023

Hello all, in this article we are going to discuss about top five state management in flutter in 2023 which are used in industrial and production level apps.

Here is the below list which is used in most of the industries.

  1. Inherited Widget.
  2. Bloc
  3. Provider.
  4. Riverpod.
  5. GetX.

Above mentioned state management libraries which are used among all the industries and most popular state management techniques.

In this artical we are gonna discuss pros and cons of all the state management techniques with examples.

Inherited Widget

Inherited widget is most powerful state management technique which is be default provided by flutter framework and all other except this we need to inject in our app through pubspec.yaml file and it is most widely used in sharing data between the widgets without have to pass data explicitly through widget constructer.

Here’s how an InheritedWidget works:

  1. Creating an InheritedWidget: You define a custom subclass of InheritedWidget. This subclass will hold the data that you want to share with descendant widgets.
class MyInheritedWidget extends InheritedWidget {
final int data;

MyInheritedWidget({required this.data, required Widget child})
: super(child: child);

@override
bool updateShouldNotify(covariant InheritedWidget oldWidget) {
return true;
}
}

Using the InheritedWidget: Wrap your widget tree with the MyInheritedWidget at the top level of your widget hierarchy, usually in the build method of your StatefulWidget. Pass the data you want to share to the MyInheritedWidget.

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MyInheritedWidget(
data: 42,
child: MaterialApp(
// Your app's content goes here.
),
);
}
}

Accessing the Inherited Data: In any descendant widget, you can access the data stored in the InheritedWidget by using the BuildContext and calling dependOnInheritedWidgetOfExactType or inheritFromWidgetOfExactType to get the reference to the MyInheritedWidget. You can then access the data property.

class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final inheritedData = context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
return Text('Data from InheritedWidget: ${inheritedData?.data}');
}
}

Updating the Inherited Data: When the data stored in the InheritedWidget needs to change, you can create a new instance of the InheritedWidget and rebuild the widget tree. Widgets that depend on the data will automatically rebuild when the data changes.

MyInheritedWidget(
data: 100,
child: MaterialApp(
// Your app's content goes here.
),
);

Pros of Inherited Widgets:

  1. Efficient Data Propagation: we can transfer data with in the widget tree using the build context.
  2. Scoped Data Sharing: Inherited Widgets allow you to create a scoped environment for data sharing.
  3. Automatic Widget Rebuilds: it will automatically rebuild when the data is changed in widget tree.
  4. Built-in Update Logic: Inherited Widgets provide the updateShouldNotify method, which allows you to implement custom logic to decide when dependent widgets should rebuild. This can help optimize your app's performance by avoiding unnecessary rebuilds.

Cons of Inherited Widgets:

  1. Boilerplate Code: Creating custom Inherited Widget subclasses and overriding methods like updateShouldNotify can lead to boilerplate code, especially for complex data sharing scenarios.
  2. Not Ideal for Mutable Data: Inherited Widgets are well-suited for sharing immutable data, but handling mutable data can be more challenging.

Bloc

Bloc is most widely used state management in industrial level and bloc is used in large scale apps. Initially when flutter was lauched it came up with the InheritedWidget state management technique but most of the developers are not compaitable with state management technique because of it’s complexity and hard to track data passing between the widgets and also it’s so confusing that business logic and ui code in the same file which makes the developer to hard to understand and track the code.

So after in a tech talk flutter community came to know that they need easier way to compactable way to develop the apps. and with the next build release the came up with the Bloc State management technique.

flutter_bloc: latest_version

You have to inject the above library in order to use Bloc state management.

Bloc: Bloc is a class where we write all the business logic, It contains the logic for processing events, managing state, and emitting state changes.

Event: Event is like a object which are emitting like when we press the button that’s the Event.

State: The Bloc emits state changes in response to events, and widgets can listen to these state changes to update their UI.

Cubit: A Cubit is a simplified version of a Bloc. It’s a lightweight, single-purpose class that doesn’t require as much boilerplate code as a full Bloc.

BlocProvider: BlocProvider is a widget which is provided by flutter_bloc package allow us to provide Bloc and Cubit Widgets to the widget tree.

BlocBuilder: BlocBuilder is a widget which is also provided by flutter_bloc which is used to rebuild the ui/widgets.

Below is the simple counter app example using flutter_bloc

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

// Define events
enum CounterEvent { increment, decrement }

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

@override
Stream<int> mapEventToState(CounterEvent event) async* {
if (event == CounterEvent.increment) {
yield state + 1;
} else if (event == CounterEvent.decrement) {
yield state - 1;
}
}
}

void main() {
runApp(
MaterialApp(
home: BlocProvider(
create: (context) => CounterBloc(),
child: CounterApp(),
),
),
);
}

class CounterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter App')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
BlocBuilder<CounterBloc, int>(
builder: (context, count) {
return Text('Count: $count');
},
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FloatingActionButton(
onPressed: () =>
context.read<CounterBloc>().add(CounterEvent.decrement),
child: Icon(Icons.remove),
),
SizedBox(width: 20),
FloatingActionButton(
onPressed: () =>
context.read<CounterBloc>().add(CounterEvent.increment),
child: Icon(Icons.add),
),
],
),
],
),
),
);
}
}

In this example, we create a simple counter app using the Bloc pattern. The CounterBloc manages the state of the counter, and we use BlocBuilder to listen to changes in the state and update the UI accordingly. Events are dispatched to the Bloc when the user interacts with the UI.

So in the next article we are gonna discuss Provider,RiverPod and GetX state management technique ,So i hope you have understood.

Thanks for reading my article to know more about flutter stay tuned and see you all the next article.

--

--