August 7, 2023

State Management in Flutter: Keeping Your App from Throwing a Temper Tantrum

The best time to establish protocols with your clients is when you onboard them.


Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.


State management can be a perplexing challenge when developing Flutter applications, but fear not! In this comprehensive guide, we’ll unravel the mysteries of state management in Flutter while keeping your app running smoothly and your developers from going bonkers. From built-in options like setState to advanced libraries like Provider, BLoC, Redux, MobX, and GetX, we’ll explore each approach’s strengths, quirks, and humorous anecdotes along the way.

What is State Management?

Imagine a world where your app’s data and user interface live harmoniously. State management refers to the process of managing and updating the data and UI components in an application. In Flutter, state management involves handling changes in the application’s state, such as user input, network responses, or data updates, and updating the UI accordingly. Effective state management ensures your app remains performant, maintainable, and devoid of developer meltdowns.

1. Built-in State Management

Once upon a time, in a land of simplicity, Flutter offered setState. We’ll examine this humble hero and his tales of updating the state and rebuilding the UI. Flutter provides a built-in mechanism for managing state using the setState method. This approach is suitable for small and simple applications with a limited number of UI components. But beware! As your app grows, setState’s limitations might have you pulling out your hair faster than a squirrel on an espresso binge.

Example of code :

In this example, we create a simple counter app that increments a counter value when the floating action button is pressed. The CounterApp widget is a stateful widget that maintains the state of the counter. The counter value is stored in the _counter variable.

When the floating action button is pressed, the _incrementCounter method is called. Inside this method, we use setState to update the state of the _counter variable. The setState function notifies Flutter that the state has changed, and the framework automatically rebuilds the UI with the updated value.

The updated counter value is then displayed in the Text widget inside the Column widget.

By using setState, we ensure that the UI reflects the updated state of the counter and that the app responds to user interactions accordingly.

2. Inheritedwidget and ScopedModel

Prepare to be amazed as we unravel the enigmatic InheritedWidget! Witness its power in sharing state across widget trees, accompanied by ScopedModel. InheritedWidget is a fundamental mechanism in Flutter for sharing state across widget trees. It allows passing down data efficiently from parent widgets to their descendants. ScopedModel, built on top of InheritedWidget, provides a convenient way to manage state by encapsulating the state object and updating the UI whenever the state changes. It is well-suited for small to medium-sized applications with moderate state management requirements.

In this example, we use the ScopedModel package along with InheritedWidget to manage the state of a counter. The CounterModel class extends Model from ScopedModel and defines the state and logic for the counter.

In the MyApp widget, we create an instance of CounterModel and pass it as the model to the ScopedModel widget. This ensures that the CounterModel is available throughout the widget tree.

In the CounterApp widget, we use ScopedModelDescendant to access the CounterModel instance and rebuild parts of the UI when the state changes. The counter value is displayed using a Text widget, and the FloatingActionButton increments the counter when pressed.

By using ScopedModel and ScopedModelDescendant, we can access the state provided by the CounterModel throughout the widget tree without explicitly passing it down. When the counter is incremented, the notifyListeners() method is called to notify the listeners (in this case, the ScopedModelDescendant widgets), and the UI is automatically updated.

3. Provider Package

Behold the mighty Provider package! Armed with the strength of InheritedWidget and ScopedModel, Provider swoops in to save the day. The Provider Package is a popular state management solution in Flutter. It builds upon the InheritedWidget and ScopedModel approaches and provides a more flexible and scalable solution for managing state. With Provider, you can create providers to expose data or objects to the widget tree and selectively rebuild only the necessary parts of the UI when the state changes. It promotes separation of concerns and reduces boilerplate code, making it suitable for medium to large-scale applications.

In this example, we use the Provider package to manage the state of a counter. The CounterModel class is a simple model that extends ChangeNotifier from the provider package.

In the MyApp widget, we create an instance of CounterModel using ChangeNotifierProvider. This provider makes the CounterModel instance available to all the descendant widgets in the widget tree.

In the CounterApp widget, we use Provider.of<CounterModel>(context) to access the CounterModel instance. This way, we can directly retrieve the counter value and call the incrementCounter method on the model.

Whenever the incrementCounter method is called and the counter is updated, the notifyListeners() method is invoked, which notifies the listeners (in this case, the Text widget displaying the counter value), and triggers a UI rebuild.

By using the Provider package, we can easily access the state provided by the CounterModel throughout the widget tree using Provider.of, and the UI automatically updates when the state changes.

4. BLoC (Business Logic Component) Pattern

Enter the BLoC pattern, where business logic meets UI separation. We’ll journey through its unidirectional data flow, streams, and testability. BLoC is an architectural pattern that decouples the business logic from the UI. It uses streams to handle state changes and provides a unidirectional flow of data. The BLoC pattern is a robust solution for complex applications with extensive state management requirements. It promotes testability, code reusability, and a clear separation of concerns.

5. Redux and MobX

Step into the ring with Redux and MobX! Marvel at Redux’s immutability and unidirectional data flow, while MobX dazzles with its reactive programming prowess. Redux and MobX are popular state management libraries from the broader Dart/Flutter ecosystem. Redux follows strict unidirectional data flow and immutability principles. It is well-suited for large applications with complex state management needs. MobX, on the other hand, provides a reactive programming model and allows for more mutable state management. It is suitable for applications with rapidly changing states.

Example of Redux

In this example, we use the Redux pattern to manage the state of a counter. We define a CounterAction enum that represents the action to increment the counter. The counterReducer function handles the state update based on the action. The main function creates a Redux store with the reducer and initial state.

The MyApp widget wraps the app in StoreProvider, which provides access to the store throughout the widget tree.

In the CounterApp widget, we use StoreConnector to connect the counter value from the Redux store to the UI. The converter function extracts the counter value from the store, and the builder function rebuilds the UI whenever the counter value changes.

The floating action button dispatches the CounterAction.increment action to the store when pressed. The StoreConnector converts the dispatching action into a callback function.

Example of MobX

In this example, we employ the MobX package to effectively manage the state of a counter. The CounterStore class serves as the central storage unit, equipped with an observable variable called “counter” and an action method called “incrementCounter()”.

To kickstart the application, we instantiate an object of the CounterStore within the main function.

The MyApp widget takes charge of wrapping the entire app using MaterialApp and ensures that the CounterStore is accessible to the CounterApp.

Inside the CounterApp widget, we leverage the Observer widget from the flutter_mobx library to keep track of changes in the counter value retrieved from the CounterStore. As soon as the counter value undergoes modifications, the user interface (UI) is automatically refreshed.

Whenever the floating action button is pressed, it triggers the execution of the incrementCounter() action method present in the CounterStore. Consequently, the counter value is updated, and MobX’s observables take care of refreshing the UI accordingly.

6. GetX

Prepare to be enchanted by GetX, the lightweight sorcerer of state management. Watch as it effortlessly weaves reactive state management, dependency injection, and routing into your Flutter app. GetX is a lightweight and powerful state management library for Flutter that emphasizes simplicity and high performance. It provides a range of features, including reactive state management, dependency injection, routing, and more. GetX is suitable for both small and large applications and offers a smooth learning curve.

In this example, we demonstrate the usage of the GetX package to manage the state of a counter. The CounterController class is responsible for handling the state and consists of an observable variable called “counter” and an action method called “incrementCounter()”.

To incorporate the CounterController into our app, we instantiate an instance of it within the main function and register it with the GetX dependency injection system using Get.put().

The MyApp widget is designed to envelop the entire app using GetMaterialApp. This configuration initializes the GetX framework and ensures that the CounterController is accessible and can be utilized throughout the widget tree.

Inside the CounterApp widget, we leverage the Obx widget provided by GetX to observe any changes in the counter value derived from the CounterController. The user interface (UI) is automatically updated whenever the counter value undergoes modifications.

Upon pressing the floating action button, the incrementCounter() action method of the CounterController is invoked. This results in an update to the counter value and triggers a UI refresh via GetX’s reactive system.


State management may be a formidable foe, but armed with knowledge and a sprinkle of humor, you can conquer it! State management is a critical aspect of building robust Flutter applications. By choosing the right state management technique, you can improve the performance, maintainability, and scalability of your projects. Whether you opt for the built-in solutions like setState, InheritedWidget and ScopedModel, or leverage external libraries like Provider, BLoC, Redux, MobX, or GetX, understanding the strengths and trade-offs of each approach is essential. Consider the complexity of your project, the team’s familiarity with the pattern, and the long-term goals of your application when making your decision. Remember, the key to sanity lies in embracing the strengths and quirks of each approach. So go forth, fluttering developer, and tame the state management beast with confidence and a smile!

August 7, 2023
min read
Subscribe to our newsletter
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Share this article

More articles