Search icon CANCEL
Subscription
0
Cart icon
Close icon
You have no products in your basket yet
Save more on your purchases!
Savings automatically calculated. No voucher code required
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
$9.99 | ALL EBOOKS & VIDEOS
Save more on purchases! Buy 2 and save 10%, Buy 3 and save 15%, Buy 5 and save 20%
MobX Quick Start Guide
MobX Quick Start Guide

MobX Quick Start Guide: Supercharge the client state in your React apps with MobX

By Pavan Podila , Michel Weststrate
$25.99 $9.99
Book Jul 2018 236 pages 1st Edition
eBook
$25.99 $9.99
Print
$32.99 $22.99
Subscription
$15.99 Monthly
eBook
$25.99 $9.99
Print
$32.99 $22.99
Subscription
$15.99 Monthly

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Buy Now
Table of content icon View table of contents Preview book icon Preview Book

MobX Quick Start Guide

Chapter 1. Introduction to State Management

The heart of your React app lives in the client state (data) and is rendered via React components. Managing this state can become tricky as you tackle user interactions (UI), perform async operations, and handle domain logic. In this chapter, we will start with a conceptual model of state management in UI, the role of side effects, and the flow of data.

Then, we will take a quick tour of MobX and introduce its core concepts. These concepts will help in drawing some comparisons with Redux. You will see that MobX turns out to be a more declarative form of Redux!

The topics covered in this chapter are as follows:

  • What is the client state?
  • The side effect model
  • A speed tour of MobX

 

The client state


The UI that you can see and manipulate on screen is the result of painting a visual representation of data. The shape of data hints at the kind of controls you provide for visualizing and manipulating this data. For example, if you have a list of items, you will likely show a List control that has an array of ListItems. Operations may include searching, paginating, filtering, sorting, or grouping the items in the list. The state of these operations is also captured as data and informs the visual representation.

The following diagram shows the direct relationship of an array with a List control:

In short, it is the data that takes on a pivotal role in describing the UI. Handling the structure and managing the changes that can happen to this data is what we commonly refer to as state management. State is just a synonym for the client-data that is rendered on the UI.

Note

State management is the act of defining the shape of data and the operations that are used to manipulate it. In the context of the UI, it is called client-side state management.

As the complexity of the UI increases, more state is accumulated on the client. It gets to a point where state becomes the ultimate source of truth for whatever we see on the screen. This approach to UI development, where we elevate the importance of the client-state, has been one of the biggest shifts in the frontend world. There is an interesting equation that captures this relationship between UI and state:

fn is a transformation function that is applied on the state (the data) that produces a corresponding UI. In fact, a subtle meaning that is hidden here is that, given the same state, fn always produces the same UI.

In the context of React, the preceding equation can be written as follows:

The only difference here is that fn takes two inputs, props and state, which is the prescribed contract of a React component.

Handling changes in state

However, the preceding equation is only giving half the story of a UI. It's true that the visual representation is derived from the state (through the transformation function, fn), but it does not account for the user operations that occur on the UI. It's like we have completely ignored the user in the equation. After all, the interface is not just used to visually represent data (state), but to also allow the manipulation of that data.

This is where we need to introduce the concept of actions that represent these user operations, which results in a change in state. Actions are the commands that you invoke as a result of various input-events that are fired. These actions cause a change in the state, which is then reflected back on the UI.

We can visualize the triad of State, UI, and Actions in the following figure:

It is worth noting that the UI does not change the state directly, but instead does it via a message-passing system by firing actions. The action encapsulates the parameters that are required to cause the appropriate change in state. The UI is responsible for capturing various kinds of user events (clicks, keyboard presses, touches, voice, and so on) and translating them into one or more actions that are then fired to change the state.

When the State changes, it notifies all of its observers (subscribers) of the change. The UI is also one of the most important subscribers that is notified. When that happens, it re-renders and updates to the new state. This system of data flow from the State into the UI is always uni-directional and has become the cornerstone of state management in modern UI development.

One of the biggest benefits of this approach is that it becomes easy to grasp how the UI is kept in sync with changing data. It also cleanly separates the responsibilities between rendering and data changes. The React framework has really embraced this uni-directional data flow and you will see this adopted and extended in MobX as well.

The side effect model


Now that we understand the roles of UI, state, and actions, we can extend this to build a mental model of how a UI needs to operate. Reflecting back on the triad of Action --> State --> UI, we can make some interesting observations that are not clearly answered. Let's think about how we would handle operations such as the following:

  • Downloading data from a server
  • Persisting data back on the server
  • Running a timer and doing something periodically
  • Executing some validation logic when some state changes

These are things that don't fit nicely in our data flow triad. Clearly, we are missing something here, right? You might argue that you could put these operations inside the UI itself and fire actions at certain times. However, that would tack on additional responsibilities to the UI, complicating its operation and also making it difficult to test. From a more academic perspective, it would also violate theSingle Responsibility Principle(SRP). SRP states that a class or a module should have only one reason to change. If we start handling additional operations in the UI, it would have more than one reason to change. 

So, it seems like we have some opposing forces in action here. We want to retain the purity of the data flow triad, handle ancillary operations such as the ones mentioned in the preceding list, and not add extra responsibilities to the UI. To balance all of these forces, we need to think about the ancillary operations as something external to the data flow triad. We call these side effects.

Side effects are a result of some state-change and are invoked by responding to the notifications coming from the state. Just like the UI, there is a handler, which we can call the side effect handler, that observes (subscribes to) the state change notifications. When a matching state change happens, the corresponding side effect is invoked:

There can be many side effect handlers in the system, and each of them is an observer of the state. When a part of the state they are observing changes, they will invoke the corresponding side effects. Now, these side effects can also cause a change in state by firing additional actions.

As an example, you could fire an action from the UI to download some data. This results in a state change to some flag, which results in notifications being fired to all the observers. A side effect handler that is observing the flag will see the change and trigger a network call to download data. When the download completes, it will fire an action to update the state with the new data.

The fact that side effects can also fire actions to update the state is an important detail that helps in completing the loop around managing state. So, it's not just the UI that can cause state changes, but also external operations (via side effects) that can affect a state change. This is the mental model of side effects, which can be used to develop your UI and manage the state that it renders. The model is quite powerful and scales very well over time. Later in this chapter and also throughout this book, you will see how MobX makes this side effect model a reality and fun to use.

With these concepts in mind, we are now ready to enter the world of MobX.

A speed tour of MobX


MobX is a reactive state management library that makes it easy to adopt the side effect model. Many of the concepts in MobX directly mirror the terminology we encountered earlier. Let's take a quick tour of these building blocks.

An observable state

The state is at the epicenter of all things happening in the UI. MobX provides a core building block, called the observable, that represents the reactive state of your application. Any JavaScript object can be used to create an observable. We can use the aptly named observable() API as follows:

import {observable} from 'mobx';

let cart = observable({
    itemCount: 0,
    modified: new Date()
});

In the preceding example, we have created a simple cart object that is also an observable. The observable() API comes from the mobx NPM package. With this simple declaration of an observable, we now have a reactive cart that keeps track of changes happening on any of its properties: itemCount and modified.

Observing the state changes

Observables alone cannot make an interesting system. We also need their counterparts, the observers. MobX gives you three different kinds of observers, each tailor-made for the use cases you will encounter in your application. The core observers are autorun, reaction, and when. We will look at each of them in more detail in the next chapter, but let's introduce autorun for now.

The autorun API takes a function as its input and executes it immediately. It also keeps track of the observables that are used inside the passed-in function. When these tracked observables change, the function is re-executed. What is really beautiful and elegant about this simple setup is that there is no extra work required to track observables and subscribe to any changes. It all just happens automatically. It's not magic, per se, but definitely an intelligent system at work, which we will cover in a later section:

import {observable, autorun} from 'mobx';

let cart = observable({
itemCount: 0,
modified: new Date()
});

autorun(() => {
console.log(`The Cart contains ${cart.itemCount} item(s).`);
});

cart.itemCount++;

// Console output:
The Cart contains 0 item(s).
The Cart contains 1 item(s).

In the preceding example, the arrow-function that was passed into autorun is executed for the first time and also when itemCount is incremented. This results in two console logs being printed. autorun makes the passed-in function (the tracking-function) an observer of the observables it references. In our case, cart.itemCount was being observed and when it was incremented, the tracking function was automatically notified, resulting in the console logs getting printed.

It's time to take action

Although we are mutating cart.itemCount directly, it is definitely not the recommended approach. Remember that the state should not be changed directly and instead should be done via actions. The use of an action also adds vocabulary to the operations that can be performed on the observable state.

In our case, we can call the state mutation that we were doing as an incrementCount action. Let's use the MobX action API to encapsulate the mutation:

import { observable, autorun, action } from 'mobx';

let cart = observable({
itemCount: 0,
modified: new Date(),
});

autorun(() => {
console.log(`The Cart contains ${cart.itemCount} item(s).`);
});

const incrementCount = action(() => {
    cart.itemCount++;
});

incrementCount();

The action API takes a function that will be called whenever the action is invoked. It may seem superfluous that we are passing a function into action, when we could just wrap the mutation inside a plain function and call the plain function instead. An astute thought, for sure. Well, there is a good reason for that. Internally, action is doing much more than being a simple wrapper. It ensures that all notifications for state changes are fired, but only after the completion of the action function.

When you are modifying a lot of observables inside your action, you don't want to be notified about every little change immediately. Instead, you want to be able to wait for all changes to complete and then fire the notifications. This makes the system more performant and also reduces the noise of too many notifications, too soon.

Going back to our example, we can see that wrapping it in an action also improves the readability of the code. By giving a specific name to the action (incrementCount) we have added vocabulary to our domain. In doing so, we can abstract the details of what is needed to actually increment the count.

Observables, observers, and actions are at the core of MobX. With these fundamental concepts, we can build some of the most powerful and complex React applications.

Note

In the MobX literature, side effects are also called reactions. Unlike actions that cause state changes, reactions are the ones responding to state changes.

Note the striking similarity with the uni-directional data flow that we saw earlier. Observables capture the state of your application. Observers (also called reactions) include both the side effect handlers as well as the UI. The actions are, well, actions that cause a change in the observable state:

A comparison with Redux

If we were to talk about state management in React and we didn't mention Redux, it would be a complete remiss. Redux is an extremely popular state management library anditspopularity stems from the fact that it simplified the original Flux architecture that was proposed by Facebook. It got rid of certain actors in Flux,such as dispatchers, which resulted in combining all the stores into one, commonly referredtoas thesingle state tree.

Note

In this section, we will do a head-on comparison with another state management library called Redux. If you have not used Redux before, you can certainly skip this section and move on to this chapter's summary.

MobX has some conceptual similarities with Redux as far as the data flow is concerned, but that is also where the similarities end. The mechanism adopted by MobX is drastically different than the one taken by Redux. Let's have a brief overview of Redux before we get into a slightly deeper-level comparison.

Redux in a nutshell

The data flow triad that we saw earlier is also applicable to Redux in its entirety. It's in the state update mechanism that Redux adds its own twist. This can be seen in the following figure:

When the UI fires the action, it is dispatched on the store. Inside the store, the action first passes through one or more middleware, where it can get acted upon and swallowed without further propagation. If the action passes through the middleware, it is sent to one or more reducers, where it can be processed to produce a new state of the store.

This new state of the store is notified to all of the subscribers, with the UI being one of them. If the state is different from the previous value that the UI has, the UI is re-rendered and brought in sync with the new state.

There are few things here that are worth highlighting:

  • From the point where the action enters the store, until the new state is computed, the entire process is synchronous.
  • Reducers are pure functions that take in the action and the previous state and produce the new state. Since they are pure functions, you cannot put side effects, such as a network call, inside a reducer.
  • Middleware is the only place where side effects can be performed, eventually resulting in an action being dispatched on the store.

If you are using Redux with React, which is the most likely combination, there is a utility library called react-redux, which can glue the store with React components. It does this through a function called connect(), which binds the store with the passed in React component. Inside connect(), the React component subscribes to the store for state-change notifications. Binding to the store via connect() means that every state change is notified to every component. This requires adding additional abstractions, such as a state-selector (using mapStateToProps) or implementing shouldComponentUpdate() to receive only the relevant state updates:

connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(Component)

We are deliberately skipping over a few other details that are required for a complete React-Redux setup, but the essentials are in place for a deeper comparison of Redux with MobX.

MobX versus Redux

In principle, MobX and Redux accomplish the same goal of providing a uni-directional data flow. The store is the central actor that manages all state changes and notifies the UI and other observers of the change in state. The mechanism to achieve that is quite different between MobX and Redux.

Redux relies on immutable state snapshots and reference-comparisons between two state snapshots to check for changes. In contrast, MobX thrives on mutable state and uses a granular notification system to track state changes. This fundamental difference in approach has implications on the Developer eXperience (DX) of using each framework. We will use the DX of building a single feature to perform a MobX versus Redux comparison.

Let's start with Redux first. Here is the list of things you have to do when working with Redux:

  • Define the shape of the state tree that will be encapsulated in the store. This is normally called initialState.
  • Identify all actions that can be performed to change this state tree. Each action is defined in the form { type: string, payload: any }. The type property is used to identify the action and payload is additional data that is carried along with the action. The action types are usually created as string constants and exported from a module.
  • Defining raw actions every time you need to dispatch them becomes very verbose. Instead, the convention is to have an action-creator function that wraps the details of the action type and takes in the payload as an argument.
  • Use the connect method to wire the React component with the store. Since every state change is notified to every component, you have to be careful to not re-render your component unnecessarily. The render should only happen when the part of the state that the component actually renders has changed (via mapStateToProps). Since every state change is notified to all connected components, it might be expensive to compute mapStateToProps every single time. To minimize these computations, it is recommended to use state selector libraries such as reselect. This increases the effort required to properly set up a performant React component. If you don't use these libraries, you have to take the onus of writing an efficient shouldComponentUpdate hook for the React component.
  • Inside every reducer, you have to make sure that you are always returning a new instance of the state anytime there is a change. Note that the reducers are usually kept separate from the initialState definition and that requires going back and forth to ensure the proper state is changed in each of the reducer actions.
  • Any side effect you want to perform has to be wrapped in middleware. For more complex side effects which involve async operations, it is better to rely on dedicated middleware libraries, such as redux-thunkredux-saga, or redux-observables. Note that this also complicates how side effects are constructed and executed. Each of the previously mentioned middleware have their own conventions and terminology. Additionally, the place where an action is dispatched is not co-located with the place where the actual side effect is handled. This results in more jumping around files to construct the mental model of how a feature is put together.
  • As the complexity of the feature increases, there is more fragmentation between actions, action-creators, middlewares, reducers, and initialState. Not having things co-located also increases the effort needed to develop a crisp mental model of a how a feature is put together.

In the MobX world, the developer experience is quite different. You will see more of this as we explore MobX throughout this book, but here is the top-level scoop:

  • Define the observable state for the feature in a store class. The various properties that can be changed and should be observed are marked with the observable API.
  • Define actions that will be needed to mutate the observable state.
  • Define all of the side effects (autorun, reaction and when) within the same feature class. The co-location of actions, reactions, and the observable state keeps the mental model crisp. MobX also supports async state updates out of the box, so no additional middleware libraries are needed to manage it.
  • Use the mobx-react package that includes the observer API, which allows the React components to connect to the observable store. You can sprinkle observer components throughout your React component tree, which is in fact the recommended approach to fine-tune component updates.
  • The advantage of using the observer is that there is no extra work needed to make the component efficient. Internally, the observer API ensures that the component is only updated when the rendered observable state changes.

MobX shifts your mindset to think of the observable state and the corresponding React components. You don't have to focus much on the wiring needed to achieve this. It is abstracted away behind simple and elegant APIs, such as observable, action, autorun, and observer.

We can go as far as saying that MobX enables a more declarative form of Redux. There are no action creators, reducers, or middleware to handle actions and produce the new state. The actions, side effects (reactions), and observable state are co-located inside the class or module. There are no complex connect() methods to glue a React component to the store. A simple observer() does the job with no extra wiring.

Note

MobX is declarative Redux. It takes the workflow associated with Redux and simplifies it considerably. Some explicit setup is no longer needed, such as the use of connect() in Container components, reselect for memoized state selection, actions, reducers and of course the middleware.

Summary


The UI is the visual equivalent of data (the state) along with interactive controls to change that state. The UI fires actions, which leads to the change in state. Side effects are external operations that are triggered due to some state change. There are observers in the system that look out for certain state changes and perform the corresponding side effects.

The data flow triad of Action --> State --> UI, coupled with side effects, creates a simple mental model of the UI. MobX strongly adheres to this mental model and you can see that reflected in its API, with observables, actions, reactions, and observers. The simplicity of this API makes it easy to tackle some of the complex interactions in UI.

If you have used Redux before, you can see that MobX reduces the ceremony needed to cause a state change and handle side effects. MobX strives to provide a declarative and reactive API for state management without compromising on simplicity. Throughout this book, this philosophy of MobX will be explored, with a deeper look at its API and real-world use cases.

In the next chapter, we will dive into the world of MobX with a first hand look at its core building blocks.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • The easiest way to learn MobX to enhance your client-side state-management
  • Understand how the concepts and components fit together
  • Work through different state management scenarios with MobX

Description

MobX is a simple and highly scalable state management library in JavaScript. Its abstractions can help you manage state in small to extremely large applications. However, if you are just starting out, it is essential to have a guide that can help you take the first steps. This book aims to be that guide that will equip you with the skills needed to use MobX and effectively handle the state management aspects of your application. You will first learn about observables, actions, and reactions: the core concepts of MobX. To see how MobX really shines and simplifies state management, you'll work through some real-world use cases. Building on these core concepts and use cases, you will learn about advanced MobX, its APIs, and libraries that extend MobX. By the end of this book, you will not only have a solid conceptual understanding of MobX, but also practical experience. You will gain the confidence to tackle many of the common state management problems in your own projects.

What you will learn

• Explore the fundamental concepts of MobX, such as observables, actions, and reactions • Use observables to track state and react to its changes with validations and visual feedback (via React Components) • Create a MobX observable from different data types • Define form data as an observable state and tackle sync and async form validations • Use the special APIs to directly manipulate observables, tracking its changes, and discovering the reasons behind a change • Tackle any state management issue you may have in your app by combining mobx-utils and mobx-state-tree • Explore the internals of the MobX reactive system by diving into its inner workings

Product Details

Country selected

Publication date : Jul 26, 2018
Length 236 pages
Edition : 1st Edition
Language : English
ISBN-13 : 9781789344837
Category :

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Buy Now

Product Details


Publication date : Jul 26, 2018
Length 236 pages
Edition : 1st Edition
Language : English
ISBN-13 : 9781789344837
Category :

Table of Contents

17 Chapters
Title Page Chevron down icon Chevron up icon
Dedication Chevron down icon Chevron up icon
Packt Upsell Chevron down icon Chevron up icon
Foreword Chevron down icon Chevron up icon
Contributors Chevron down icon Chevron up icon
Preface Chevron down icon Chevron up icon
1. Introduction to State Management Chevron down icon Chevron up icon
2. Observables, Actions, and Reactions Chevron down icon Chevron up icon
3. A React App with MobX Chevron down icon Chevron up icon
4. Crafting the Observable Tree Chevron down icon Chevron up icon
5. Derivations, Actions, and Reactions Chevron down icon Chevron up icon
6. Handling Real-World Use Cases Chevron down icon Chevron up icon
7. Special API for Special Cases Chevron down icon Chevron up icon
8. Exploring mobx-utils and mobx-state-tree Chevron down icon Chevron up icon
9. Mobx Internals Chevron down icon Chevron up icon
1. Other Books You May Enjoy Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Empty star icon Empty star icon Empty star icon Empty star icon Empty star icon 0
(0 Ratings)
5 star 0%
4 star 0%
3 star 0%
2 star 0%
1 star 0%
Top Reviews
No reviews found
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.