State Management in Flutter with Mobx
- Mobile
State Management in Flutter with Mobx
State Management in Flutter with
For every mobile application developer, it is very important to handle the state of the application in an optimized way. Handling state is nothing but to handle the application’s implicit data within the application and between different screens.
In flutter, there are many ways to handle state management. Let’s have a look at some state management practices.
1. Inherited Widget.
2. Providers
3. setState
4. Redux
5. BLoC/Rx
6. Mobx
7. Riverpod
8. GetX
As you can see we can achieve state management in many ways.
Now the question arises why we should use the state management in flutter?
So here is the answer.
Why use state management
Let’s take an example for a better understanding. Suppose there is a stateful widget class named A. A button in A-class navigates the user to the new Stateful widget class named B. Again there is a button in the B class which navigates the user to the new stateful widget class named C.
Now there is a variable named totalStudent in class A. Users are using this same variable in classes B and C as well. Let suppose the totalStudent value has been changed in class B and the user gets back on the first screen and I am not passing the updated value of that variable to the previous class through Navigator. Now how can we see the change over there?
So, for getting rid of the above problem we can use State Management. State management provides a better code structure and better code readability.
Now Mobx comes into the picture. By using Mobx we can achieve state management and better code architecture.
Mobx separates the business logic from the UI section so that programmers can easily understand the code and no messy code will be shown on the screen while developing.
MobX is a state-management library that makes it simple to connect the reactive data of your application with the UI (or any observer). This wiring is completely automatic and feels very natural. As the application-developer, you focus purely on what reactive-data needs to be consumed in the UI (and elsewhere) without worrying about keeping the two in sync.
Steps that has been flowed while applying Mobx are:
- A UI (or an ObStay on watchserver) will fire an Action
- The Action will trigger a mutation in the Observable
- The UI will react to the change of the Observable.
Prerequisites for using Mobx
Before getting started with this article, you need a working knowledge of Flutter. If you need help getting started, you can follow the codelabs on the Flutter website. You also need to have the installations outlined below on your machine:
- Flutter SDK, version 1.0 or later. (This comes with a Dart SDK installation)
- A development environment, one of:
- Android Studio, version 3.0 or later, or
- IntelliJ IDEA, version 2017.1 or later, or
- Visual Studio Code.
However, irrespective of the choice of IDE used, to aid effective development through the provision of tools for editing and refactoring your Flutter application, you will need an installation of the Dart and Flutter plugins.
Installation of Mobx
Add the following dependencies to your pubspec.yaml file:
1 2 3 |
dependencies: mobx: ^2.0.0 flutter_mobx: ^2.0.0 |
Next, add the following dev_dependencies:
1 2 3 |
dev_dependencies: build_runner: ^1.12.2 mobx_codegen: ^2.0.0 |
In your project folder, run this command to fetch all the packages:
1 |
flutter packages get |
Add a Store
_Now, let’s create a MobX store. A store in MobX is a way of collecting the related observable state under one class. The store allows us to use annotations and keeps the code simple. Create a new file counter.dart in \lib folder and add the following code to it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import 'package:mobx/mobx.dart'; // Include generated file part 'counter.g.dart'; // This is the class used by rest of your codebase class Counter = _Counter with _$Counter; // The store-class abstract class _Counter with Store { @observable int value = 0; @action void increment() { value++; } } |
The interesting parts here are:
- The abstract class _Counter includes the Store mixin. All of your store-related code should be placed inside this abstract class. We create a Counter class to blend in the code from the build_runner.
- The generated code will be inside the part file: counter.g.dart, which we include with the part directive. Without this, the build_runner will not produce any output. The generated file contains the _$Counter mixin.
Note
It is essential to use the proper casing for the file name, else the build_runner will not generate any output. Since our file is called counter.dart, the part file must be named as counter.g.dart (note the lowercase letters).
- The @observable annotation to mark the value as observable.
- Use of @action to mark the increment() method as an action.
Run the following command inside your project folder. This generates the code in counter.g.dart, which we have already included as part file.
1 |
flutter packages pub run build_runner build |
On the command-line, here’s the output we got from running it. Yours might be slightly different.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
➜ [mobx_getting_started]> flutter packages pub run build_runner build [INFO] Generating build script... [INFO] Generating build script completed, took 319ms [INFO] Initializing inputs [INFO] Reading cached asset graph... [INFO] Reading cached asset graph completed, took 76ms [INFO] Checking for updates since last build... [INFO] Checking for updates since last build completed, took 705ms [INFO] Running build... [INFO] 1.1s elapsed, 0/3 actions completed. [INFO] 6.7s elapsed, 2/3 actions completed. [INFO] 7.7s elapsed, 3/3 actions completed. [INFO] Running build completed, took 7.7s [INFO] Caching finalized dependency graph... [INFO] Caching finalized dependency graph completed, took 33ms [INFO] Succeeded after 7.8s with 2 outputs (6 actions) |
Stay on watch
If you are making changes to the store and want to generate *.g.dart files automatically, you can use the following command:
1 |
flutter packages pub run build_runner watch |
Connect the Store and add an Observer to your Widget
Now comes the part where we connect the MobX store to the Widget. In your main.dart file, replace the code with the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'counter.dart'; // Import the Counter final counter = Counter(); // Instantiate the store void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'MobX', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(), ); } } class MyHomePage extends StatelessWidget { const MyHomePage(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('MobX Counter'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'You have pushed the button this many times:', ), // Wrapping in the Observer will automatically re-render on changes to counter.value Observer( builder: (_) => Text( '${counter.value}', style: Theme.of(context).textTheme.headline4, ), ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: counter.increment, tooltip: 'Increment', child: Icon(Icons.add), ), ); } } |
You will notice above that we have not used any StatefulWidget instances! The state is stored in the Counter store and the Observer widget reads the counter.value to render the count. Just the simple act of reading the counter.value is enough for the Observer to start tracking and re-render on changes.
And we are Done!!
Now all your business logic is separated from the UIs and the code looks cleaner.
Related content
Auriga: Leveling Up for Enterprise Growth!
Auriga’s journey began in 2010 crafting products for India’s