Mobx Providers In Flutter

Mobx Providers In Flutter :

MobX is a one of state management, originally developed for JavaScript but now is there for Dart also. MobX is a Battle tested state management library Transparently Functional Reactive programming (TFRP).
Widgets are the basic building blocks that can be reused at a later time. They can be Classified into — stateless(No internal state exist) & stateful(Dynamic) widgets .

SetState has its own limitations:
1) Share More state across components — Internal state management become troublesome when you need to share more states across components.
2) Distant leaf components need access to states — Intermediary components doesn’t need to know becomes a problem as data gets shared to all pass through components.

Mobx
mobx_codegen: a code generation library for MobX that allows usage of MobX annotations
build_runner: a stand-alone library to run code generation operations
mobx: Dart port of MobX for writing state-modifying logic
flutter_mobx: Flutter integration for MobX that provides the Observer widget that automatically rebuilds based on changes to observable state

Flutter Mobx using .g file geneated terminal command
1) flutter packages pub run build_runner build
2) flutter packages pub run build_runner watch
3) flutter packages pub run build_runner watch –delete-conflicting-outputs

  • Observables are variables which represent the reactive-state of our application. They are also called ‘Event Generators’ because the state or value of an observable changes from time to time.
  • Actions are functions that decide how to mutate the observables. Because of this property, they are also called ‘Mutators’.
  • Computed Observables are values which depend upon observables and get triggered when the observable they depend on, changes its state.
  • Observer Widgets are a special type of widget which acts as a listener to the observable properties being rendered on the screen, and simply changes the state and re-renders them whenever any change is observed.

Counter Package :

counter_store.dart

import 'package:mobx/mobx.dart';
import 'package:pattern_mobx_provider/base/mobx/mobx_base/mobx_base.dart';
part 'counter_store.g.dart';

class CounterStore = _CounterStore with _$CounterStore;

abstract class _CounterStore extends MobxBase with Store {
  _CounterStore():_counter=0;
  @observable
  int _counter;

  int get counter => _counter;

  @action
  void increment() => _counter++;

  void dispose() {}
}

counter_store.g.dart

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'counter_store.dart';

// **************************************************************************
// StoreGenerator
// **************************************************************************

// ignore_for_file: non_constant_identifier_names, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic

mixin _$CounterStore on _CounterStore, Store {
  final _$_counterAtom = Atom(name: '_CounterStore._counter');

  @override
  int get _counter {
    _$_counterAtom.context.enforceReadPolicy(_$_counterAtom);
    _$_counterAtom.reportObserved();
    return super._counter;
  }

  @override
  set _counter(int value) {
    _$_counterAtom.context.conditionallyRunInAction(() {
      super._counter = value;
      _$_counterAtom.reportChanged();
    }, _$_counterAtom, name: '${_$_counterAtom.name}_set');
  }

  final _$_CounterStoreActionController =
      ActionController(name: '_CounterStore');

  @override
  void increment() {
    final _$actionInfo = _$_CounterStoreActionController.startAction();
    try {
      return super.increment();
    } finally {
      _$_CounterStoreActionController.endAction(_$actionInfo);
    }
  }
}

counter_widget.dart

import 'package:flutter/material.dart';
import 'package:pattern_mobx_provider/base/mobx/mobx_providers/mobx_stateful_provider.dart';
import 'counter_store.dart';

class CounterWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MobxStatefulProvider<CounterStore>(
      store: CounterStore(),
      builder: (context, store) {
        return Scaffold(
          floatingActionButton: FloatingActionButton(
              onPressed: store.increment, child: Icon(Icons.add)),
          appBar: AppBar(
            title: Text('mobx provider example'),
          ),
          body: Center(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text('counter value is ${store.counter}'),
              ],
            ),
          ),
        );
      },
    );
  }
}

mobx Package

mobx_base

  • mobx_base.dart
  • mobx_b ase.g.dart

mobx_base.dart

import 'package:mobx/mobx.dart';
part 'mobx_base.g.dart';

enum StoreState { loading, sucess, initial, error }

///this is the base class for all mobx classes that need to be attached to the ui.
///it contains some helper states and function that make it easier
///in the ui for determining which widget you should show to the user.
///despite the class has [Store] mixin , you should write [with store] exciplictly
///in your own class in order to generate the code.
abstract class MobxBase = _MobxBase with _$MobxBase;

abstract class _MobxBase with Store {
  _MobxBase() : _state = StoreState.initial;
  @observable
  StoreState _state;

  ///get the state of the store
  StoreState get state => _state;

  bool get isLoading => _state == StoreState.loading;
  bool get isError => _state == StoreState.error;
  bool get isSuccess => _state == StoreState.sucess;
  bool get isInitial => _state == StoreState.initial;
  @action
  void changeState(StoreState state) => _state = state;
  @action
  void toLoadingState() => _state = StoreState.loading;
  @action
  void toSuccessState() => _state = StoreState.sucess;
  @action
  void toErrorState() => _state = StoreState.error;
  @action
  void toInitialState() => _state = StoreState.initial;

  ///this function is called when the [observer stateful provider] is disposed
  void dispose();
}

mobx_b ase.g.dart

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'mobx_base.dart';

// **************************************************************************
// StoreGenerator
// **************************************************************************

// ignore_for_file: non_constant_identifier_names, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic

mixin _$MobxBase on _MobxBase, Store {
  final _$_stateAtom = Atom(name: '_MobxBase._state');

  @override
  StoreState get _state {
    _$_stateAtom.context.enforceReadPolicy(_$_stateAtom);
    _$_stateAtom.reportObserved();
    return super._state;
  }

  @override
  set _state(StoreState value) {
    _$_stateAtom.context.conditionallyRunInAction(() {
      super._state = value;
      _$_stateAtom.reportChanged();
    }, _$_stateAtom, name: '${_$_stateAtom.name}_set');
  }

  final _$_MobxBaseActionController = ActionController(name: '_MobxBase');

  @override
  void changeState(StoreState state) {
    final _$actionInfo = _$_MobxBaseActionController.startAction();
    try {
      return super.changeState(state);
    } finally {
      _$_MobxBaseActionController.endAction(_$actionInfo);
    }
  }

  @override
  void toLoadingState() {
    final _$actionInfo = _$_MobxBaseActionController.startAction();
    try {
      return super.toLoadingState();
    } finally {
      _$_MobxBaseActionController.endAction(_$actionInfo);
    }
  }

  @override
  void toSuccessState() {
    final _$actionInfo = _$_MobxBaseActionController.startAction();
    try {
      return super.toSuccessState();
    } finally {
      _$_MobxBaseActionController.endAction(_$actionInfo);
    }
  }

  @override
  void toErrorState() {
    final _$actionInfo = _$_MobxBaseActionController.startAction();
    try {
      return super.toErrorState();
    } finally {
      _$_MobxBaseActionController.endAction(_$actionInfo);
    }
  }

  @override
  void toInitialState() {
    final _$actionInfo = _$_MobxBaseActionController.startAction();
    try {
      return super.toInitialState();
    } finally {
      _$_MobxBaseActionController.endAction(_$actionInfo);
    }
  }
}

mobx_providers Package

  • mobx_stateful_provider.dart
  • mobx_stateless_provider.dart

mobx_stateful_provider.dart

import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:pattern_mobx_provider/base/mobx/mobx_base/mobx_base.dart';

///This is like the [Observer stateless Provider] but it contains [Stateful widget]
///instead of [Stateless Widget], this allows you to call a function [initFunction]
/// that you want to be invoked in the [init State]
/// it also preserve the [state of the store] in hot reload
/// if you press hot reload with the default [observer Provider] it'll lose its state
/// when the [current widget] is removed from the widget tree the [StatefulObserverProvider] will
/// call [disopse function] for the store
/// this package is inspired from [Filled Stacks] package [view model provider]
class MobxStatefulProvider<T extends MobxBase> extends StatefulObserverWidget {
  final T store;
  final Widget Function(BuildContext context, T store) builder;
  final void Function(T store) initFunction;

  MobxStatefulProvider({
    ///the name of your widget , that's used for debuging purposes only
    ///it's the same as the name parameter in the [observer] widgets
    String name,
    Key key,
    @required this.store,
    @required this.builder,
    this.initFunction,
  }) : super(key: key, name: name);
  @override
  _MobxStatefulProviderState<T> createState() =>
      _MobxStatefulProviderState<T>();
}

class _MobxStatefulProviderState<T extends MobxBase>
    extends State<MobxStatefulProvider<T>> {
  T _store;
  @override
  void initState() {
    super.initState();
    _store = widget.store;
    if (widget.initFunction != null) widget.initFunction(_store);
  }

  @override
  void dispose() {
    _store.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => widget.builder(context, _store);
}

mobx_stateless_provider.dart

import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:pattern_mobx_provider/base/mobx/mobx_base/mobx_base.dart';

///This widget is like default [observer widget] but with
///easier way to bind your stores with the UI
///this widget is extends [stateless Observer widget] which extends [stateless wisget]
///so it's basically a [stateless widget]
///NOTE: hence this is a [stateless widget] it doesn't hold any state , even the state of
///ITS STORE, the store should be SINGLETON and be binded with the widget by injector service
///like provider , get_it ,etc
/// this package is inspired from [Filled Stacks] package [view model provider]
class MobxStatelessProvider<T extends MobxBase>
    extends StatelessObserverWidget {
  final T store;

  final Widget Function(BuildContext context, T store) builder;

  MobxStatelessProvider({
    ///the name of your widget , that's used for debuging purposes only
    ///it's the same as the name parameter in the [observer] widget
    String name,
    Key key,
    @required this.store,
    @required this.builder,
  }) : super(key: key, name: name);
  @override
  Widget build(BuildContext context) => builder(context, store);
}

main.dart

import 'package:flutter/material.dart';

import 'counter/counter_widget.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CounterWidget(),
    );
  }
}

pubspec.yaml

name: pattern_mobx_provider
description: A new Flutter application.
version: 1.0.0+1

environment:
  sdk: ">=2.1.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  mobx:
  flutter_mobx:
  cupertino_icons:

dev_dependencies:
  build_runner:
  mobx_codegen:
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true

The flutter tutorial  is a website that bring you the latest and amazing resources of code. All the languages codes are included in this website. The languages like flutter, android, java,kotlin etc.with the help of this languages any user can develop the beautiful application

For more information about Flutter. visit www.fluttertutorial.in