By Paul Halliday, founder, Developer. school

It is well known that state management is an area where every software project needs continuous iteration. It’s not a “one off” job, but a constant effort to ensure that the best practices you follow keep your project maintainable.

To use MobX efficiently in Flutter, follow the following principles:

  1. We can access observables in any state (that is, variables that change as our application runs).
  2. We can display these states in the View and respond to Action intents.
  3. We can modify the state to update the observable and the corresponding View.

So what’s the advantage? The answer is, it’s super easy to do it all through MobX! The CodeGen tool does most of the template work for us.

Initialize the project

Let’s start by creating a brand new Flutter project:

# New Flutter project
$ flutter create f_mobx && cd f_mobx
 
# Open in VS Code
$ code .
Copy the code

Next, we need to pull dependencies (dependencies and dev_dependencies) from pubspec.yaml:

dependencies: 
 flutter:
    sdk: flutter
 
  mobx:
  flutter_mobx:
 
dev_dependencies:
  flutter_test:
    sdk: flutter
 
  build_runner: ^ 1.3.1
  mobx_codegen:
Copy the code

Dart can then create a brand new MaterialApp to place our CounterPage.

import 'package:f_mobx/pages/counter_page.dart';
import 'package:flutter/material.dart';
 
void main() => runApp(MyApp());
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return newMaterialApp( home: CounterPage(), ); }}Copy the code

Next, we need to create the CounterPage in lib/pages/ Counter_page.dart and finish building the user interface. It includes an increase button and a decrease button.

import 'package:flutter/material.dart';
 
class CounterPage extends StatelessWidget {
 
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: AppBar(
          title: Text('Flutter and MobX'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'Counter',
                style: TextStyle(fontSize: 30.0),
              ),
              Text(
                '0', 
                style: TextStyle(fontSize: 42.0),
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  FlatButton.icon(
                    icon: Icon(Icons.add),
                    label: Text('Add'),
                    onPressed: () {},
                  ),
                  FlatButton.icon(
                    icon: Icon(Icons.remove),
                    label: Text('Remove'), onPressed: () {}, ), ), ], ) ], ), )); }}Copy the code

Create the state of the counter

That’s great! We are now in the lib/store/counter/counter. The dart created our counter. Now, let’s look at the code, line by line:

import 'package:mobx/mobx.dart';
 
// This is our generated file (we'll see this soon!)
part 'counter.g.dart';
 
// We expose this to be used throughout our project
class Counter = _Counter with _$Counter;
 
// Our store class
abstract class _Counter with Store {
  @observable
  int value = 1;
 
  @action
  void increment() {
    value++;
  }
 
  @action
  voiddecrement() { value--; }}Copy the code
  1. We importmobx.dart“, so you can access the Store and other functions.
  2. Next, we usepartThe automatically generated part of a syntax combination class. We haven’t used the generator yet, but don’t worry, we’ll do it in the next section.
  3. Next, we will be exposedCounterClass, which will be associated with the generated mobx-bound_$CounterClass used together.
  4. Finally, we create one using the Store class_CounterAnd decide on one@observableProperties and@actionsTo identify areas with which the Store can interact.

MobX already does most of the heavy lifting for us, so we don’t need to worry about how the underlying implementation works.

Now that we have the Counter class, let’s run build_Runner and mobx_codegen in that project directory on the terminal with the following command:

$ flutter packages pub run build_runner watch
Copy the code

We should now see the generated counter. G.art file. It looks something like this:

part of 'counter.dart';
mixin _$Counter on _Counter, Store {
  final _$valueAtom = Atom(name: '_Counter.value');
 
  @override
  int get value {
    _$valueAtom.reportObserved();
    return super.value;
  }
 
  @override
  set value(int value) {
    _$valueAtom.context.checkIfStateModificationsAreAllowed(_$valueAtom);
    super.value = value;
    _$valueAtom.reportChanged();
  }
 
  final _$_CounterActionController = ActionController(name: '_Counter');
 
  @override
  void increment() {
    final _$actionInfo = _$_CounterActionController.startAction();
    try {
      return super.increment();
    } finally{ _$_CounterActionController.endAction(_$actionInfo); }}@override
  void decrement() {
    final _$actionInfo = _$_CounterActionController.startAction();
    try {
      return super.decrement();
    } finally{ _$_CounterActionController.endAction(_$actionInfo); }}}Copy the code

None of these things we need to achieve ourselves! Isn’t it great?

Bind to Store

Next, we need to bind counter_page.dart to the Counter Store. Let’s see what it looks like again and explore further:

import 'package:flut_mobx/store/counter/counter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
 
class CounterPage extends StatelessWidget {
  final Counter counter = Counter();
 
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: AppBar(
          title: Text('Flutter and MobX'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'Counter',
                style: TextStyle(fontSize: 30.0),
              ),
              Observer(
                builder: (_) =>
                    Text('${counter.value}', style: TextStyle(fontSize: 42.0)),
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  FlatButton.icon(
                    icon: Icon(Icons.add),
                    label: Text('Add'),
                    onPressed: counter.increment,
                  ),
                  FlatButton.icon(
                    icon: Icon(Icons.remove),
                    label: Text('Remove'), onPressed: counter.decrement, ), ], ) ], ), )); }}Copy the code

Let’s dig deeper:

  1. We importflutter_mobxAnd our Counter Store, so we can use them later.
  2. Next, we initializeCounterAnd name itcounter, then we can easily listen to the value of the observable, or emitActions: Final Counter Counter = Counter();
  3. We use the Observer to listencounter.valueThe value of the.
  4. We bind the onPressed event tocounter.incrementcounter.decrementThey willactionSend to Store.

The above code combined to complete our small counter application!

conclusion

Hope this introduction to MobX has helped you. I am currently continuing to explore best practices for Flutter state management, so I look forward to further updates to this series in the future.

: the original developer. School/flutter – sta… Note: localization and distribution of the article & video have been authorized by the author himself

Thank you

  • By Paul Halliday
  • Chinese Subtitles: Alex, Xin Lei
  • Jia Kang, Xin Lei
  • The first figure: Lynn