MobX for the Dart language. Hassle-free, reactive state-management for your Dart and Flutter apps.

Overview

Language: English | PortuguΓͺs | Chinese

mobx.dart



pub package pub package pub package

Build Status Publish Coverage Status Netlify Status

Join the chat at https://discord.gg/dNHY52k

MobX for the Dart language.

Supercharge the state-management in your Dart apps with Transparent Functional Reactive Programming (TFRP)

Introduction

MobX is a state-management library that makes it simple to connect the reactive data of your application with the UI. 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.

It's not really magic but it does have some smarts around what is being consumed (observables) and where (reactions), and automatically tracks it for you. When the observables change, all reactions are re-run. What's interesting is that these reactions can be anything from a simple console log, a network call to re-rendering the UI.

MobX has been a very effective library for the JavaScript apps and this port to the Dart language aims to bring the same levels of productivity.

Sponsors

We are very thankful to our sponsors to make us part of their Open Source Software (OSS) program. [Become a sponsor]

Get Started

Follow along with the Getting Started guide on the MobX.dart Website.

Go deep

For a deeper coverage of MobX, do check out MobX Quick Start Guide. Although the book uses the JavaScript version of MobX, the concepts are 100% applicable to Dart and Flutter.

Core Concepts

MobX Triad

At the heart of MobX are three important concepts: Observables, Actions and Reactions.

Observables

Observables represent the reactive-state of your application. They can be simple scalars to complex object trees. By defining the state of the application as a tree of observables, you can expose a reactive-state-tree that the UI (or other observers in the app) consume.

A simple reactive-counter is represented by the following observable:

import 'package:mobx/mobx.dart';

final counter = Observable(0);

More complex observables, such as classes, can be created as well.

class Counter {
  Counter() {
    increment = Action(_increment);
  }

  final _value = Observable(0);
  int get value => _value.value;

  set value(int newValue) => _value.value = newValue;
  Action increment;

  void _increment() {
    _value.value++;
  }
}

On first sight, this does look like some boilerplate code which can quickly go out of hand! This is why we added mobx_codegen to the mix that allows you to replace the above code with the following:

import 'package:mobx/mobx.dart';

part 'counter.g.dart';

class Counter = CounterBase with _$Counter;

abstract class CounterBase with Store {
  @observable
  int value = 0;

  @action
  void increment() {
    value++;
  }
}

Note the use of annotations to mark the observable properties of the class. Yes, there is some header boilerplate here but its fixed for any class. As you build more complex classes this boilerplate will fade away and you will mostly focus on the code within the braces.

Note: Annotations are available via the mobx_codegen package.

Computed Observables

What can be derived, should be derived. Automatically.

The state of your application consists of core-state and derived-state. The core-state is state inherent to the domain you are dealing with. For example, if you have a Contact entity, the firstName and lastName form the core-state of Contact. However, fullName is derived-state, obtained by combining firstName and lastName.

Such derived state, that depends on core-state or other derived-state is called a Computed Observable. It is automatically kept in sync when its underlying observables change.

State in MobX = Core-State + Derived-State

import 'package:mobx/mobx.dart';

part 'contact.g.dart';

class Contact = ContactBase with _$Contact;

abstract class ContactBase with Store {
  @observable
  String firstName;

  @observable
  String lastName;

  @computed
  String get fullName => '$firstName, $lastName';

}

In the example above fullName is automatically kept in sync if either firstName and/or lastName changes.

Actions

Actions are how you mutate the observables. Rather than mutating them directly, actions add a semantic meaning to the mutations. For example, instead of just doing value++, firing an increment() action carries more meaning. Besides, actions also batch up all the notifications and ensure the changes are notified only after they complete. Thus the observers are notified only upon the atomic completion of the action.

Note that actions can also be nested, in which case the notifications go out when the top-most action has completed.

final counter = Observable(0);

final increment = Action((){
  counter.value++;
});

When creating actions inside a class, you can take advantage of annotations!

import 'package:mobx/mobx.dart';

part 'counter.g.dart';

class Counter = CounterBase with _$Counter;

abstract class CounterBase with Store {
  @observable
  int value = 0;

  @action
  void increment() {
    value++;
  }
}

Asynchronous Actions

MobX.dart handles asynchronous actions automatically and does not require wrapping the code with runInAction.

@observable
String stuff = '';

@observable
loading = false;

@action
Future<void> loadStuff() async {
  loading = true; //This notifies observers
  stuff = await fetchStuff();
  loading = false; //This also notifies observers
}

Reactions

Reactions complete the MobX triad of observables, actions and reactions. They are the observers of the reactive-system and get notified whenever an observable they track is changed. Reactions come in few flavors as listed below. All of them return a ReactionDisposer, a function that can be called to dispose the reaction.

One striking feature of reactions is that they automatically track all the observables without any explicit wiring. The act of reading an observable within a reaction is enough to track it!

The code you write with MobX appears to be literally ceremony-free!

ReactionDisposer autorun(Function(Reaction) fn)

Runs the reaction immediately and also on any change in the observables used inside fn.

import 'package:mobx/mobx.dart';

String greeting = Observable('Hello World');

final dispose = autorun((_){
  print(greeting.value);
});

greeting.value = 'Hello MobX';

// Done with the autorun()
dispose();


// Prints:
// Hello World
// Hello MobX

ReactionDisposer reaction<T>(T Function(Reaction) predicate, void Function(T) effect)

Monitors the observables used inside the predicate() function and runs the effect() when the predicate returns a different value. Only the observables inside predicate() are tracked.

import 'package:mobx/mobx.dart';

String greeting = Observable('Hello World');

final dispose = reaction((_) => greeting.value, (msg) => print(msg));

greeting.value = 'Hello MobX'; // Cause a change

// Done with the reaction()
dispose();


// Prints:
// Hello MobX

ReactionDisposer when(bool Function(Reaction) predicate, void Function() effect)

Monitors the observables used inside predicate() and runs the effect() when it returns true. After the effect() is run, when automatically disposes itself. So you can think of when as a one-time reaction. You can also dispose when() pre-maturely.

import 'package:mobx/mobx.dart';

String greeting = Observable('Hello World');

final dispose = when((_) => greeting.value == 'Hello MobX', () => print('Someone greeted MobX'));

greeting.value = 'Hello MobX'; // Causes a change, runs effect and disposes


// Prints:
// Someone greeted MobX

Future<void> asyncWhen(bool Function(Reaction) predicate)

Similar to when but returns a Future, which is fulfilled when the predicate() returns true. This is a convenient way of waiting for the predicate() to turn true.

final completed = Observable(false);

void waitForCompletion() async {
  await asyncWhen(() => _completed.value == true);

  print('Completed');
}

Observer

One of the most visual reactions in the app is the UI. The Observer widget (which is part of the flutter_mobx package), provides a granular observer of the observables used in its builder function. Whenever these observables change, Observer rebuilds and renders.

Below is the Counter example in its entirety.

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

part 'counter.g.dart';

class Counter = CounterBase with _$Counter;

abstract class CounterBase with Store {
  @observable
  int value = 0;

  @action
  void increment() {
    value++;
  }
}

class CounterExample extends StatefulWidget {
  const CounterExample({Key key}) : super(key: key);

  @override
  _CounterExampleState createState() => _CounterExampleState();
}

class _CounterExampleState extends State<CounterExample> {
  final _counter = Counter();

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: const Text('Counter'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                'You have pushed the button this many times:',
              ),
              Observer(
                  builder: (_) => Text(
                        '${_counter.value}',
                        style: const TextStyle(fontSize: 20),
                      )),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _counter.increment,
          tooltip: 'Increment',
          child: const Icon(Icons.add),
        ),
      );
}

Contributing

If you have read up till here, then πŸŽ‰ πŸŽ‰ πŸŽ‰ . There are couple of ways in which you can contribute to the growing community of MobX.dart.

  • Pick up any issue marked with "good first issue"
  • Propose any feature, enhancement
  • Report a bug
  • Fix a bug
  • Participate in a discussion and help in decision making
  • Write and improve some documentation. Documentation is super critical and its importance cannot be overstated!
  • Send in a Pull Request :-)
  • Chime in and Join the chat at https://discord.gg/dNHY52k

Contributors ✨

All Contributors

Thanks goes to these wonderful people (emoji key):


Pavan Podila

πŸ’» πŸ“– πŸ‘€

katis

πŸ’» πŸ€” πŸ‘€ ⚠️

Scott Hyndman

πŸ’» πŸ€” πŸ‘€ ⚠️

Michael Bui

πŸ’» πŸ“– πŸ‘€ πŸ’‘

Remi Rousselet

πŸ’» πŸ“– πŸ‘€

adiaKhaitan

πŸ“–

Jacob Moura

πŸ’» πŸ“– 🌍

Daniel Albuquerque

🌍

Marco Scannadinari

πŸ“–

lsaudon

πŸ’» πŸ“–

Efthymis Sarmpanis

πŸ’»

Giri Jeedigunta

πŸ“– πŸ’‘

Hebri Ramnath Nayak

πŸ“–

Robert Brunhage

πŸ“–

Brady Trainor

πŸ“–

Kushagra Saxena

πŸ“– πŸ’‘

Pedro Massango

🌍

Peter Czibik

πŸ’»

Luan Nico

πŸ“–

Kobi

πŸ’»

Ryan

πŸ“–

Ivan Terekhin

πŸ’»

Yoav RofΓ©

πŸ“–

Mateusz Wojtczak

πŸ“–

Timur Artikov

πŸ’»

Saurabh Sohoni

πŸ“–

renanzdm

πŸ“–

Rachman Chavik

πŸ’»

Nathan Cabasso

πŸ› πŸ’»

geisterfurz007

πŸ“– πŸ–‹

Romuald Barbe

πŸ’»

Alexander Mazuruk

πŸ’‘

Alberto Bonacina

πŸ“–

Roland Ibragimov

πŸ“–

zyzhao

πŸ“–

Xinhai Wang

πŸ“–

Henry Mayer

πŸ’» ⚠️

Sergey

πŸ’» ⚠️

Jason Rai

πŸ“–

Joshua de Guzman

πŸ’‘

Jan Hertlein

πŸ“–

Evo Stamatov

πŸ’»

Davi Eduardo

πŸ“–

Leonardo Custodio

πŸ’» πŸ“–

Prince Srivastava

πŸ’‘ πŸ’»

Muhammad Muhajir

πŸ“–

D

πŸ“–

David Martos

πŸ’»

Issa Nimaga

πŸ“–

AscΓͺnio

πŸ’»

This project follows the all-contributors specification. Contributions of any kind welcome!

Comments
  • Code generator design

    Code generator design

    Since we've started working on the code generation, I thought I'd open a discussion thread about its design.

    We need at least three working annotations, @observable, @computed and @action.

    The generator will find all classes with a specific annotation (@observable, @store?) and creates a private subclass _$ParentClass that overrides the annotated fields, getters and methods with Mobx magic.

    I'll use parts of this annotated class in the next sections:

    @store // tbd
    class User {
      @observable
      String firstName = 'Jane';
    
      @observable
      String lastName = 'Doe';
    
      @computed
      String get fullName => '$firstName $lastName';
    
      @action
      void updateNames({String firstName, String lastName }) {
        ...
      }
    }
    

    @observable

    The first approach I tried was with a hidden Observable<T> field:

    class _$User {
      final _$firstName = Observable<String>(null, name: 'User.firstName');
    
      @override
      String get firstName => _$firstName.value;
    
      @override
      set firstName(String value) => _$firstName.value = value;
    }
    

    This had some downsides. One was that the User creates storage for the original firstName field which then ends up unused. Second is that the initialization becomes slightly more complicated. The initial value must be copied from the superclasses field, and the field must be nulled so that it doesn't keep the initial value in memory. Code would look something like this:

    class _$User {
     _$User() {
       _$firstName.value = super.firstName;
       super.firstName = null;
     }
    
     final _$firstName = Observable<String>(null, name: 'User.firstName');
    
      @override
      String get firstName => _$firstName.value;
    
      @override
      set firstName(String value) => _$firstName.value = value;
    }
    

    My second attempt was with an Atom which made the initialization a non-issue, since it just uses the original field:

    class _$User {
     final _$firstNameAtom = Atom(name: 'User.firstName');
    
      @override
      String get firstName {
         _$firstNameAtom.reportObserved();
        return super.firstName;
      }
    
      @override
      set firstName(String value) {
        super.firstName = value;
        _$firstNameAtom.reportChanged();
      }
    }
    

    I think the Atom method is better, for the reasons above.

    @computed

    Computed should be simple, just override a getter and use the original one:

    class _$User {
      _$User() {
        _$fullNameComputed = Computed(() => super.fullName);
      }
    
     Computed<String> _$fullNameComputed;
    
      @override
      String get fullName => _$fullNameComputed.value;
    }
    

    @action

    The @action annotation has a name conflict with the current action() builder. We could remove action() and replace it with multiple action variants for different function arities: action0<R>(() => ...), action1<A, R>((a: A) => ...), action2<A, B, R>((a: A, b: B) => ...). The names are ugly, but they could be used by the codegen and I think that once the code generator is done, people won't use the raw versions much.

    class _$User {
      _$User() {
        _$updateNames = action2((String a, String b) => super.updateNames(firstName: a, lastName: b));
      }
    
      Action2<String, String ,void> _$updateNames;
    
      @override
      void updateNames({String firstName, String lastName}) {
        _$updateNames(firstName, lastName);
      }
    }
    

    Named vs. positional arguments will add complexity in the generator.

    Automatic conversions

    Mobx JS makes objects and arrays automatically observable when you use the @observable decorator. You can opt-out by using @observable.ref decorator instead.

    Dart can't support the feature for classes, but it would be possible (sort of) for collections like Maps and Lists.

    I'm not a fan of it as a default, and using an ObservableList is not much harder than using a List.

    class ShoppingCart {
      @observable
      List<Item> items = [];
    }
    

    vs.

    class ShoppingCart {
      @observable
      List<Item> items = ObservableList();
    }
    

    Since we can't modify the actual list assigned to the variable like in JS but only wrap it, it might be confusing that the non-observable List you passed to ShoppingCart.items is suddenly a reactive list when accessed from items.

    final items = [];
    
    final cart = ShoppingCart();
    cart.items = items; // Supposedly items and cart.items are the same list
    
    cart.items.add(Item()); // Mobx reacts to the change :)
    
    items.add(Item()); // Mobx misses the change :(
    

    Constructors

    The generator should be able to create a constructor that matches the superclass factory that delegates to the subclass:

    class User {
      // 
      User._(this.firstName, this.lastName);
    
      // Dart can delegate to the subclass constructor with this syntax
      factory User({String firstName, String lastName}) => _$User; // This could also determine the name of the subclass?
    }
    
    class _$User {
      _$User({String firstName, String lastName})
        : super._(firstName, lastName}) {
      }
    }
    

    observe() support in annotated classes

    We would want the generated classes to be supported in devtools etc, but the problem is that the Atoms, Computeds etc are hidden in the subclass. It would be ugly to expose them as public, and you'd have to cast the User to _$User.

    Another way would be to define an interface like:

    abstract class Store {
      void observe(String field, listener);
    }
    

    make the annotated class abstract, and implement Store:

    abstract class User implements Store {
    }
    

    Then the code generation could implement Store automatically:

    class _$User extends User {
      void observe(String field, listener) {
        if (field == 'firstName') { ... }
        // etc.
      }
    }
    

    Store interface could also expose a Map of observable fields, so devtools could iterate and analyze them.

    opened by katis 67
  • Migrate MobX for NNBD / null safety

    Migrate MobX for NNBD / null safety

    MobX will need to be migrated to NNBD. Most packages have started releasing pre-release -nullsafety versions now that it's in beta support.

    https://medium.com/dartlang/announcing-dart-null-safety-beta-87610fee6730

    opened by acoutts 56
  • Flutter API

    Flutter API

    Last night I thought I'd try to use Mobx with Flutter and created a simple widget based on the design of mobx-react and Flutter's ValueListenableBuilder:

    import 'package:flutter/widgets.dart';
    import 'package:mobx/mobx.dart';
    
    void noOp() {}
    
    class Observer extends StatefulWidget {
      const Observer({Key key, @required this.builder}) : super(key: key);
    
      final Widget Function(BuildContext) builder;
    
      @override
      State<StatefulWidget> createState() => _ObserverState();
    }
    
    class _ObserverState extends State<Observer> {
      bool _isBuildPending = false;
    
      Reaction _buildReaction;
    
      @override
      void initState() {
        super.initState();
    
        _buildReaction = Reaction(mobxContext, () {
          if (_isBuildPending) {
            return;
          }
    
          _isBuildPending = true;
          if (!mounted) {
            return;
          }
    
          setState(noOp);
        });
      }
    
      @override
      Widget build(BuildContext context) {
        _isBuildPending = false;
        Widget result;
        _buildReaction.track(() {
          result = widget.builder(context);
        });
        return result;
      }
    }
    

    usage:

    class Greeter extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => _GreeterState();
    }
    
    class _GreeterState extends State<Greeter> {
      final name = observable('Jane');
    
      @override
      Widget build(BuildContext context) => Observer(builder: (context) {
        return Text('Hello, ${name.value}');
      });
    }
    

    It does seem to work and could be a starting point for the flutter_mobx API. Probably the life cycle of widgets will bring all kinds of problems like in mobx-react.

    discussion 
    opened by katis 48
  • [Request] More manageable Form at scale

    [Request] More manageable Form at scale

    I'm going with MobX on my new project which involves a lot of Forms (hundreds) and Fields (10 to 50)

    At core MobX solve a lot of concerns but it's not easy to copy the Form example at scale when you have a lot of fields.

    There are two stores to handle, values and errors also you should not forget to init disposers.

    There's an ObservableList that handle specific modifications and react accordingly. I'd like to have an ObservableFormField that would handle Fields.

    So much handwritten code is really error prone when working on real business forms entries

    Thank you for your feedback !

    I'm not sure how to architect all this but I'll be happy to find logic per field at one place only.

    @observable
    ObservableFormField<String> name = ObservableFormField<String>(
       name:'firstname',
       validator : ...
       error : errorBuilder<String>(..) => ...
    )
    
    @action
    setName(String value) => name.value = value
    
    enhancement discussion investigation 
    opened by Solido 45
  • References to classes generated by other build-generated types are resolved to dynamic (Moor, SuperEnum, BuiltValue)

    References to classes generated by other build-generated types are resolved to dynamic (Moor, SuperEnum, BuiltValue)

    mobx_codegen resolves a moor generated class to dynamic. I suspect this is a limitation in the build framework, and how the analyzer is set up to resolve against generated code.

    image

    image

    Versions:

    flutter_mobx 0.3.6
    mobx 0.4.0+1
    mobx_codegen 0.4.0+1
    build_runner 1.7.3
    

    Originally posted by @irvine5k in https://github.com/mobxjs/mobx.dart/issues/381#issuecomment-577308858

    bug 
    opened by shyndman 42
  • observable list isn't a valid override of

    observable list isn't a valid override of

    After update the mobx version I'm having issue with all of my Stores that have a observable list. Lets say that I have the following code:

    class EventsStore = _EventsStore with _$EventsStore;
    
    abstract class _EventsStore with Store {
    
      final EventsService eventsService;
    
      _EventsStore(this.eventsService) : assert(eventsService != null);
    
    //...
    
      @observable
      List<Event> _events = <Event>[];
    
    //...
    }
    

    I'm receiving a error saying:

    error: '_$EventsStore._events' ('dynamic Function()') isn't a valid override of '_EventsStore._events' ('List<Event> Function()').

    If I remve the _events property and run flutter run build_runner again the error disappear and it goes back to normal

    bug 
    opened by pedromassango 42
  • Usage example with Firebase FireStore

    Usage example with Firebase FireStore

    The most common usecase for most of the developers will be using state management with a cloud database source.. like Firebase FireStore.

    Any example of implementing such CRUD actions will be great. I am willing to use MobX for the same usecase.

    discussion 
    opened by Purus 40
  • Add generation of toString method when @tostring annotation is used

    Add generation of toString method when @tostring annotation is used

    Be careful: pubscpec.yaml contain dependency_overrides in order to expose @tostring annotation from new mobx version !

    Remove @store annotation from mobx lib and test Add @tostring annotation in mobx lib and test Add @tostring annotation recognition in mobx_codegen Add toString method generation on computed and observables when @tostring is used Add test on toString method generation

    Feature request: mobx_codegen: allow generating toString method for Store class mobxjs#174 Previous pull request closed by error: mobxjs#391

    Sorry for keeping all my local history details :(

    opened by hawkbee1 30
  • dart:ui types not handled by mobx_codegen properly on Flutter stable/beta

    dart:ui types not handled by mobx_codegen properly on Flutter stable/beta

    Some people in the community are reporting to me that the Color class when placed in Observable is generating Dynamic.

      @observable
      Color colorPrimary = null;
    

    And generated it:

      @override
      dynamic get colorPrimary {
        _$colorPrimaryAtom.context.enforceReadPolicy(_$colorPrimaryAtom);
        _$colorPrimaryAtom.reportObserved();
        return super.colorPrimary;
      }
    

    The Color class is blocked somehow and we are unable to solve it, has anyone had this problem?

    bug 
    opened by Bwolfs2 29
  • Simplify Store creation with the @store annotation

    Simplify Store creation with the @store annotation

    Based on the discussion in #217, we can simplify the Store creation with the use of an annotation: @store.

    The ideal way given the code-gen constraints is to have something like this:

    part 'counter.g.dart'; // This file will contain the _$Counter mixin
    
    @store
    class Counter with _$Counter {
      @observable
      int value = 0;
    
      @action
      void increment() {
        value++;
      }
    
    }
    

    The generated code will be as before with some slight changes on the mixin declaration:

    // GENERATED CODE - DO NOT MODIFY BY HAND
    
    part of 'counter.dart';
    
    // **************************************************************************
    // StoreGenerator
    // **************************************************************************
    
    // ignore_for_file: non_constant_identifier_names, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars
    
    mixin _$Counter on Counter {
      final _$valueAtom = Atom(name: '_Counter.value');
    
      @override
      int get value {
        _$valueAtom.context.enforceReadPolicy(_$valueAtom);
        _$valueAtom.reportObserved();
        return super.value;
      }
    
      @override
      set value(int value) {
        // Since we are conditionally wrapping within an Action, there is no need to enforceWritePolicy
        _$valueAtom.context.conditionallyRunInAction(() {
          super.value = value;
          _$valueAtom.reportChanged();
        }, _$valueAtom, name: '${_$valueAtom.name}_set');
      }
    
      final _$_CounterActionController = ActionController(name: '_Counter');
    
      @override
      void increment() {
        final _$actionInfo = _$_CounterActionController.startAction();
        try {
          return super.increment();
        } finally {
          _$_CounterActionController.endAction(_$actionInfo);
        }
      }
    }
    
    

    @rrousselGit, can you confirm this is doable?

    opened by pavanpodila 29
  • no outputs on build_runner build

    no outputs on build_runner build

    Hello, I can't seem to get build_runner to generate anything.

    Running

    flutter packages pub run build_runner clean && flutter packages pub run build_runner build --delete-conflicting-outputs
    

    outputs the following:

    [INFO] Generating build script...
    [INFO] Generating build script completed, took 454ms
    
    [INFO] Creating build script snapshot......
    [INFO] Creating build script snapshot... completed, took 18.6s
    
    [INFO] Initializing inputs
    [INFO] Building new asset graph...
    [INFO] Building new asset graph completed, took 1.0s
    
    [INFO] Checking for unexpected pre-existing outputs....
    [INFO] Checking for unexpected pre-existing outputs. completed, took 1ms
    
    [INFO] Running build...
    [INFO] 1.1s elapsed, 0/16 actions completed.
    [INFO] 2.1s elapsed, 0/16 actions completed.
    [INFO] 3.3s elapsed, 0/16 actions completed.
    [INFO] 4.4s elapsed, 0/16 actions completed.
    [INFO] 5.5s elapsed, 0/16 actions completed.
    [INFO] 6.5s elapsed, 0/16 actions completed.
    [INFO] 7.5s elapsed, 0/16 actions completed.
    [INFO] 8.7s elapsed, 0/16 actions completed.
    [INFO] 19.6s elapsed, 0/16 actions completed.
    [WARNING] No actions completed for 19.6s, waiting on:
      - json_serializable:json_serializable on test/widget_test.dart
      - json_serializable:json_serializable on lib/view_models/event_selected_view_model.dart
      - json_serializable:json_serializable on lib/repositories/UserRepository.dart
      - json_serializable:json_serializable on lib/models/Organization.dart
      - json_serializable:json_serializable on lib/models/User.dart
      .. and 11 more
    
    [INFO] 21.0s elapsed, 2/18 actions completed.
    [INFO] 22.0s elapsed, 12/27 actions completed.
    [INFO] 23.4s elapsed, 18/33 actions completed.
    [INFO] 24.5s elapsed, 60/76 actions completed.
    [WARNING] mobx_codegen:mobx_generator on lib/mobx/Authentication.dart:
    Missing "part 'Authentication.g.dart';".
    [INFO] 26.2s elapsed, 134/141 actions completed.
    [INFO] Running build completed, took 26.4s
    
    [INFO] Caching finalized dependency graph...
    [INFO] Caching finalized dependency graph completed, took 110ms
    
    [INFO] Succeeded after 26.5s with 14 outputs (148 actions)
    

    The only outputs are from json_serializable.

    My store file looks like this:

    import 'package:mobx/mobx.dart';
    part "authentication.g.dart";
    
    class Authentication = AuthenticationBase with _$Authentication;
    
    abstract class AuthenticationBase with Store {
    
    }
    

    I saw

    Missing "part 'Authentication.g.dart';".

    So I removed that line + the class line:

    import 'package:mobx/mobx.dart';
    
    abstract class AuthenticationBase with Store {
    
    }
    

    I then get this:

    [INFO] Generating build script...
    [INFO] Generating build script completed, took 586ms
    
    [INFO] Creating build script snapshot......
    [INFO] Creating build script snapshot... completed, took 22.5s
    
    [INFO] Initializing inputs
    [INFO] Building new asset graph...
    [INFO] Building new asset graph completed, took 1.7s
    
    [INFO] Checking for unexpected pre-existing outputs....
    [INFO] Checking for unexpected pre-existing outputs. completed, took 2ms
    
    [INFO] Running build...
    [INFO] 1.1s elapsed, 0/16 actions completed.
    [INFO] 2.2s elapsed, 0/16 actions completed.
    [INFO] 3.2s elapsed, 0/16 actions completed.
    [INFO] 4.3s elapsed, 0/16 actions completed.
    [INFO] 5.5s elapsed, 0/16 actions completed.
    [INFO] 6.6s elapsed, 0/16 actions completed.
    [INFO] 7.6s elapsed, 0/16 actions completed.
    [INFO] 8.9s elapsed, 0/16 actions completed.
    [INFO] 9.9s elapsed, 0/16 actions completed.
    [INFO] 20.3s elapsed, 1/16 actions completed.
    [INFO] 21.4s elapsed, 1/17 actions completed.
    [INFO] 23.3s elapsed, 17/29 actions completed.
    [INFO] 24.7s elapsed, 48/63 actions completed.
    [INFO] 25.7s elapsed, 116/123 actions completed.
    [INFO] Running build completed, took 26.1s
    
    [INFO] Caching finalized dependency graph...
    [INFO] Caching finalized dependency graph completed, took 106ms
    
    [INFO] Succeeded after 26.2s with 14 outputs (148 actions)
    

    Still without generated files.

    Pubspec.yaml:

    name: buggerino_flutter
    description: A new Flutter project.
    
    # The following defines the version and build number for your application.
    # A version number is three numbers separated by dots, like 1.2.43
    # followed by an optional build number separated by a +.
    # Both the version and the builder number may be overridden in flutter
    # build by specifying --build-name and --build-number, respectively.
    # In Android, build-name is used as versionName while build-number used as versionCode.
    # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
    # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
    # Read more about iOS versioning at
    # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
    version: 1.0.0+1
    
    environment:
      sdk: ">=2.2.2 <3.0.0"
    
    dependencies:
      flutter:
        sdk: flutter
    
      # The following adds the Cupertino Icons font to your application.
      # Use with the CupertinoIcons class for iOS style icons.
      cupertino_icons: ^0.1.2
      flutter_keychain: ^1.0.0
      http: ^0.12.0+2
      bloc: ^2.0.0
      flutter_bloc: ^2.0.0
      equatable: ^0.6.1
      json_annotation: ^3.0.0
      mobx: ^0.4.0+1
      flutter_mobx: ^0.3.6
    
    dev_dependencies:
      flutter_test:
        sdk: flutter
      build_runner: ^1.7.2
      json_serializable: ^3.2.0
      mobx_codegen: ^0.4.0+1
    
    
    # For information on the generic Dart part of this file, see the
    # following page: https://dart.dev/tools/pub/pubspec
    
    # The following section is specific to Flutter.
    flutter:
    
      # The following line ensures that the Material Icons font is
      # included with your application, so that you can use the icons in
      # the material Icons class.
      uses-material-design: true
    
      # To add assets to your application, add an assets section, like this:
      # assets:
      #  - images/a_dot_burr.jpeg
      #  - images/a_dot_ham.jpeg
    
      # An image asset can refer to one or more resolution-specific "variants", see
      # https://flutter.dev/assets-and-images/#resolution-aware.
    
      # For details regarding adding assets from package dependencies, see
      # https://flutter.dev/assets-and-images/#from-packages
    
      # To add custom fonts to your application, add a fonts section here,
      # in this "flutter" section. Each entry in this list should have a
      # "family" key with the font family name, and a "fonts" key with a
      # list giving the asset and other descriptors for the font. For
      # example:
      # fonts:
      #   - family: Schyler
      #     fonts:
      #       - asset: fonts/Schyler-Regular.ttf
      #       - asset: fonts/Schyler-Italic.ttf
      #         style: italic
      #   - family: Trajan Pro
      #     fonts:
      #       - asset: fonts/TrajanPro.ttf
      #       - asset: fonts/TrajanPro_Bold.ttf
      #         weight: 700
      #
      # For details regarding fonts from package dependencies,
      # see https://flutter.dev/custom-fonts/#from-packages
    
    opened by jordyvandomselaar 22
  • MobX Generator - Simplify writing store code (Realm dart example)

    MobX Generator - Simplify writing store code (Realm dart example)

    Hello, Thanks for your work.

    Writing a store is too verbose. The Realm team generates the class this way. Is it possible to take inspiration from what they have done?

    From

    class Counter = CounterBase with _$Counter;
    
    abstract class CounterBase with Store {
    }
    

    To

    class _Counter with Store {
    }
    

    After the generator create this :

    class Counter extends _Counter {
    }
    

    Here is the sample realm repository https://github.com/realm/realm-dart/tree/main/example/bin

    Thanks

    opened by mohachouch 0
  • mobx utils

    mobx utils

    added mobx utils

    • obs from Listenable
    • obs from ValueNotifier
    • Stream of obs values

    at least we should have ability to convert obs values into stream since streams are very useful for async world https://github.com/mobxjs/mobx-utils#tostream for example we could convert computed field to stream and solve #860

    added reporting manual change for observable and collections there are some cases when you should need to report change, for example if using collections extensions (sortBy), or writing own function that converts some class similar to Listenable.

    opened by altynbek132 5
  • ObservableValueSpyEvent missing for changes in an ObservableList

    ObservableValueSpyEvent missing for changes in an ObservableList

    I expected that when I spy like this:

      mainContext.spy((event) {
        if (event is ObservableValueSpyEvent) print(event);
      });
    

    I also get notified when I add, remove issues to the list, but unfortunetly no event is fired in this case.

    // The store-class
    abstract class TeamBase with Store {
      TeamBase(this.name);
    
      @observable
      String name;
    
      @observable
      ObservableList<Issue> issues = ObservableList();
    
      @action
      void addIssue() => issues.add(Issue(issues.length.toString()));
    }
    
    
    // This is the class used by rest of your codebase
    class Issue = IssueBase with _$Issue;
    
    // The store-class
    abstract class IssueBase with Store {
      IssueBase(this.name);
    
      @observable
      String name;
    }
    
    

    Is this a bug or not supportet? The Mobx.js does seem to have this implemented: https://mobx.js.org/analyzing-reactivity.html#spy

    PS: I want to build something like this: https://www.youtube.com/watch?t=2171&v=WxK11RsLqp4&feature=youtu.be&ab_channel=Fraktio

    opened by HerrNiklasRaab 0
  • Separate State from Actions

    Separate State from Actions

    Hello, I wonder if it's possible to organize Mobx as Actions<->View<->State

    I would like to see my state as a single object, or single Observable state tree. And access it from actions completely separated from the state.

    Multiple stores have been the source of all my problems since React 0.11, and having actions inside the Store makes them more like Controllers with Models, at least I feel it like that.

    
      // Somehow create a single observable tree
      Map SingleStateTree = {
        'user': {
          'username': 'rambo',
          'loggedIn': true,
        },
        'twitts': [
          { 'user': 'rambo', 'text': 'hello world' }
        ],
      };
    
      // actions can change whatever nested state in our single state tree
      void action() {
        Map newTwitt = { 'user': 'mobx', 'text': 'its cool!' };
        // This reports changes to observables
        SingleStateTree['twitts'].add(newTwitt);
      }
     
      // Observers work as they normally do
      // ...
    

    Hopefully, this makes sense, I want to see my state as a single object with nested objects, and not as a Store with nested Stores that need to communicate between them, if actions are separated and have access to all state they don't need to.

    Maybe I'm asking too much from dart without mirrors but maybe there's a way, or maybe it's completely possible with a bit of extra boilerplate and I'm just missing it XD.

    kind of like Baobab.js, Cerebral.js or Overmind.js

    Thank you very much, Mobx seems very good!

    opened by leon-volq 1
  • How to pass `this` to link stores?

    How to pass `this` to link stores?

    I see that in the js documentation this is how you link stores

    class RootStore {
        constructor() {
            this.userStore = new UserStore(this)
            this.todoStore = new TodoStore(this)
        }
    }
    
    class UserStore {
        constructor(rootStore) {
            this.rootStore = rootStore
        }
    
        getTodos(user) {
            // Access todoStore through the root store.
            return this.rootStore.todoStore.todos.filter(todo => todo.author === user)
        }
    }
    
    class TodoStore {
        todos = []
        rootStore
    
        constructor(rootStore) {
            makeAutoObservable(this, { rootStore: false })
            this.rootStore = rootStore
        }
    }
    

    I'm confused as to how I can do this with mobx.

    I have a RootStore

    class RootStore = RootStoreBase with _$RootStore;
    
    abstract class RootStoreBase with Store {
      // Not sure if this is correct either.
      late LikesStore likesStore;
      RootStoreBase() {
        likesStore = LikesStore(this);
      }
    }
    

    How can I set this up in my LikesStore?

    opened by DanMossa 2
Owner
MobX
Simple, scalable state management
MobX
A flutter boilerplate project with GetX state management.

flutter_getx_boilerplate Languages: English (this file), Chinese. Introduction During my study of Flutter, I have been using the flutter_bloc state ma

Kevin Zhang 234 Jan 5, 2023
Flutter MVU architecture/state management package

mvu_flutter No mutability. No builders. No connectors. No reducers. No StreamControllers and subscription management. A truly declarative state manage

Yakov Karpov 7 Jul 29, 2021
Simple global state management for Flutter

Slices Slices is a minimalist state manegement, focused specifically for applications that needs a global state where different "pieces" of the applic

Erick 5 Jun 15, 2021
The modular state management solution for flutter.

The modular state management solution for flutter. Easy debugging : each event is predictable and goes into a single pipeline Centralized state : soli

AloΓ―s Deniel 44 Jul 6, 2022
Flutter State Management with provider :rocket:

Flutter - Gerenciamento de Estados com Provider Objetivos ao completar os estudos Aprenda a gerenciar o estado da sua aplicação com Single Source of T

Tiago Barbosa 0 Dec 6, 2021
A predictable state management library that helps implement the BLoC design pattern

A predictable state management library that helps implement the BLoC design pattern. Package Pub bloc bloc_test flutter_bloc angular_bloc hydrated_blo

Felix Angelov 9.9k Dec 31, 2022
Another state management solution

VxState VxState is a state management library built for Flutter apps with focus on simplicity. It is inspired by StoreKeeper & libraries like Redux, V

Pawan Kumar 42 Dec 24, 2022
London App Brewery State Management Project

todey_flutter A new Flutter application. Getting Started This project is a starting point for a Flutter application. A few resources to get you starte

null 0 Nov 1, 2021
Manage the state of your widgets using imperative programming concepts.

Imperative Flutter Manage the state of your widgets using imperative programming concepts. Setup Intall imperative_flutter package in pubspec.yaml dep

Jeovane Santos 5 Aug 20, 2022
A simple way to access state while robust and testable.

A state-management library that: catches programming errors at compile time rather than at runtime removes nesting for listening/combining objects ens

Remi Rousselet 3.9k Jan 3, 2023
Example of use bloc + freezed with a state that contains a list

blocfreezedlistexample A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you s

Leynier GutiΓ©rrez GonzΓ‘lez 2 Mar 21, 2022
Timer based on provider state manager

timer_provider Timer based on provider state manager Getting Started This project is a starting point for a Flutter application. A few resources to ge

Π•Π»ΠΈΠ·Π°Π²Π΅Ρ‚Π° Π›ΠΎΠ±ΠΎΠ΄ΠΈΠ½Π° 0 Nov 6, 2021
Trip management mobile Application

HereYouGO Trip management mobile Application This app will help you Track your expense during your trips. Track your trip destinations and the sub tri

Krupali Mehta 4 Jul 7, 2022
Functional programming in Dart and Flutter. All the main functional programming types and patterns fully documented, tested, and with examples.

Fpdart Functional programming in Dart and Flutter. All the main functional programming types and patterns fully documented, tested, and with examples.

Sandro Maglione 275 Dec 26, 2022
Megaflixz is a movie app for the movie lover in you. Includes all new and upcoming movies and TV series. Also has an option to save movies to watch later list

MegaflixZ MegaflixZ is a movie app for the movie lover in you. It is an app that displays new and upcoming movies and tv series. Team members Deepak M

Deepak Mathews Koshy 11 Aug 23, 2021
Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get.

Languages: English (this file), Indonesian, Urdu, Chinese, Brazilian Portuguese, Spanish, Russian, Polish, Korean, French. About Get Installing Counte

Jonny Borges 8k Jan 8, 2023
App to Watch Animes And Read Manga.

App To Watch Anime And Read Manga NOTE: Manga Section Contains 18+ content. Sometimes App may take some time to load. Constants Folder is removed from

null 8 Sep 12, 2021
A light, powerful and reactive state management for Flutter Apps.

A light, powerful and reactive state management. Features ⚑️ Build for speed. ?? Reduce boilerplate code significantly. ?? Improve code readability. ?

2devs 3 Dec 15, 2022
A powerful state machine for MobX management, that can be used in almost any application state.

A powerful state machine for MobX management, which can be used in almost any application state. It has 3 states - loading, success, error - and is pe

Daniel Magri 8 Oct 31, 2022
Nexus is a state management library that makes it easy to create and consume your application's reactive data to the user interface.

Nexus ?? Nexus is a state management library that makes it easy to create and consume your application's reactive data to the user interface. With nex

Gor Mkhitaryan 3 Sep 7, 2022