Core Concepts | MobX.dart (2024)

Core Concepts | MobX.dart (1)

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

Observables

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

The term reactive data means that a change to data causes a notification tobe fired to every interested observer. It is the application of the classicObserver Design Pattern.

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;
late Action increment;

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

On first sight, this does look like some boilerplate code which can quickly goout of hand! This is why we added Core Concepts | MobX.dart (2) to the mixthat 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 buildmore complex classes, this boilerplate will fade away and you will mostly focuson the code within the braces.

Note: Annotations are available via the Core Concepts | MobX.dart (3)package.

The above code is part of the Counter Example.

For those who have experience with the JavaScript version of MobX, it'simportant to note that deep observability doesn't apply in the Dart version ofMobX. This is because Dart is a statically typed language and there's nosupport for reflection (no dart:mirrors) in Flutter applications. Therefore,if a complex object is marked as @observable then MobX will not be able toautomatically track changes to the object's fields. Should you need changetracking at the field level, it's better to mark them individually with the@observable annotation.

Computed Observables

What can be derived, should be derived. Automatically.

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

Such derived state, which depends on core-state or other derived-state iscalled a Computed Observable. It is automatically kept in sync when itsunderlying 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 eitherfirstName 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 justdoing value++, firing an increment() action carries more meaning. Besides,actions also batch up all the notifications and ensure the changes are notifiedonly after they complete. Thus, the observers are notified only upon the atomiccompletion of the action.

Note that actions can also be nested, in which case the notifications go outwhen 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++;
}
}

Reactions

Reactions complete the MobX triad of observables, actions andreactions. They are the observers of the reactive-system and get notifiedwhenever an observable they track is changed. Reactions come in few flavors aslisted below. All of them return a ReactionDisposer, a function that can becalled to dispose the reaction.

One striking feature of reactions is that they automatically track all theobservables without any explicit wiring. The act of reading an observablewithin 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 usedinside fn.

import 'package:mobx/mobx.dart';

final 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) fn, void Function(T) effect)

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

import 'package:mobx/mobx.dart';

final 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 automaticallydisposes itself. So you can think of when as a one-time reaction. You canalso dispose when() pre-maturely.

import 'package:mobx/mobx.dart';

final 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 thepredicate() returns true. This is a convenient way of waiting for thepredicate() 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 Core Concepts | MobX.dart (4)), provides a granularobserver of the observables used in its builder function. Whenever theseobservables 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();

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

class CounterExampleState extends State<CounterExample> {
final Counter counter = Counter();

@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
title: const Text('MobX 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: 40),
)),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: counter.increment,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}

Core Concepts | MobX.dart (5)

Deeper coverage

There are some articles written byMichel Weststrate which go into thephilosophy of MobX. Definitely worth reading them.

Core Concepts | MobX.dart (2024)

FAQs

What is MobX in react? ›

Anything that can be derived from the application state, should be. Automatically. MobX is a signal based, battle-tested library that makes state management simple and scalable by transparently applying functional reactive programming. The philosophy behind MobX is simple: 😙

Why should I use MobX? ›

Actions are all the things that alter the state. MobX will make sure that all changes to the application state caused by your actions are automatically processed by all derivations and reactions. Synchronously and glitch-free.

What is MobX in flutter? ›

MobX is a library for reactively managing the state of your applications. Use the power of observables, actions, and reactions to supercharge your Dart and Flutter apps.

What is MobX state tree? ›

What is MobX-State-Tree? Technically speaking, MobX-State-Tree (also known as MST) is a state container system built on MobX, a functional reactive state library.

Why MobX is better than Redux? ›

Redux stands out for its structured nature and predictability, making it ideal for complex projects. In contrast, MobX offers a concise syntax and simplified reactivity, making it better for applications seeking simplicity.

Is MobX faster than Redux? ›

In terms of performance, redux is less efficient than Mobx. Redux process action, after dispatching action updates the UI. In complex circ*mstances, it could be a performance concern sometimes. Redux may not be efficient when we compare it with other libraries, but it avoids unnecessary rendering.

Which is best MobX or Redux? ›

Redux provides performance optimizations through the use of immutable data and a strict update cycle. MobX, on the other hand, uses fine-grained reactivity, which can lead to better performance in certain scenarios.

What is MobX vs Redux? ›

Redux assists in the creation of applications that behave consistently across all platforms. It also simplifies the writing, testing, and debugging of code for developers. MobX is a battle-tested library that makes state management simple and scalable by transparently applying functional reactive programming (TFRP).

Should I use Redux or MobX? ›

Mobx is mainly used to develop the application fast and in less time. Redux developed applications generally take time because of their complexity. Mobx is less maintainable. Redux is more maintainable.

Who uses MobX? ›

Projects and companies using MobX
ProjectInformation
Forward ExpInternational Freight Forwarder (mostly Ocean Freight Container Shipments)
CoinbaseLeading bitcoin brokerage platform
Productive EdgeDigital Consultancy (Web, Mobile and Software Development Firm)
2M2.RURussian real-estate classifieds website.
40 more rows

Should I use SwiftUI or Flutter? ›

There's no clear winner. Each framework shines in different areas. Choose Flutter for cross-platform reach, rapid development, and design flexibility. Opt for SwiftUI for native iOS performance, tight Apple integration, and a familiar Swift experience.

Why use Redux in Flutter? ›

Integrating Redux into a Flutter app simplifies state management and provides a consistent and predictable data flow.

Why use MobX in flutter? ›

Understanding Flutter MobX

The Observer widget in MobX, which is a part of the build method, ensures that whenever any observable it's tracking observables values changes, it triggers a new build. It's a reaction to changes in the state.

Is MobX immutable? ›

mobx-state-tree (also known as "MST") is a state container that combines the simplicity and ease of mutable data with the traceability of immutable data and the reactiveness and performance of observable data.

How do I migrate from MobX to Redux? ›

To migrate from MobX to Redux, follow these steps: Install Dependencies: Install Redux and React-Redux packages. Create Redux Store: Use createStore to create a Redux store, defining initial state and reducers with combineReducers. Define Actions: Define actions and action creators.

Is MobX the same as Redux? ›

Redux and MobX are two popular state management libraries that provide a robust solution for managing state in ReactJS applications. Redux is a predictable state container for JavaScript apps, while MobX is a simple, scalable, and battle-tested state management solution.

What is Redux and MobX? ›

Redux and MobX are both state management libraries commonly used in JavaScript and React applications. While they serve similar purposes, there are some differences in their approach and usage.

References

Top Articles
Latest Posts
Article information

Author: Geoffrey Lueilwitz

Last Updated:

Views: 6326

Rating: 5 / 5 (60 voted)

Reviews: 91% of readers found this page helpful

Author information

Name: Geoffrey Lueilwitz

Birthday: 1997-03-23

Address: 74183 Thomas Course, Port Micheal, OK 55446-1529

Phone: +13408645881558

Job: Global Representative

Hobby: Sailing, Vehicle restoration, Rowing, Ghost hunting, Scrapbooking, Rugby, Board sports

Introduction: My name is Geoffrey Lueilwitz, I am a zealous, encouraging, sparkling, enchanting, graceful, faithful, nice person who loves writing and wants to share my knowledge and understanding with you.