State Management With MobX
Application state can be managed in many different ways. In simple applications you may not need an explicit state management strategy. But when your application grows to have a lot of views or complex UI where the same data needs to be displayed in multiple places or when there are many dependencies between UI controls it may become difficult to keep the application in a consistent state when the user interacts with the application. If you don’t have a good state management strategy it can be easy to introduce new bugs when changing application logic.
This is where a state management library like MobX can help and make the application easier to maintain and extend. Here we concentrate on an approach to store all shared frontend state in a central MobX state store which will be the single source of truth for the application state. Then it’s easy to display the state data (or anything that can be derived from it) anywhere in the UI so that the data is automatically updated everywhere where it is displayed whenever the data is updated in the state store.
Using MobX in Your Application
Vaadin recommends to use the MobX library to manage frontend state in your apps.
When using Lit that means you should extend the MobxLitElement
class instead of LitElement
.
When your views are based on MobxLitElement
, any MobX observables used in the render()
method are automatically tracked so that any change to those observables is automatically reflected in the view.
Creating a new Vaadin Fusion project with Vaadin Start (or Vaadin CLI) already takes care of setting up the basics for you by providing a MobX store (named AppState
) and View
and Layout
helper base classes for your application views and layouts.
Both View
and Layout
extend MobxLitElement
and you may expand the AppState
store with your own observables and actions to be used in your views.
Caution | MobX decorators with TypeScript MobX has experimental support for decorators ( For more information see Enabling decorators in MobX documentation. |
Creating a Data Store
Here is a minimal example of a MobX store that contains one observable property (quote
) and one action (setQuote()
) for updating that property.
Here the store is initialized and exported on the last line so that you can import the same store instance into any view or component to access the shared state.
import { makeAutoObservable } from 'mobx';
class MyState {
quote: string = `Anything that can be derived from the application state,
should be. Automatically. - MobX documentation`;
constructor() {
makeAutoObservable(this);
}
setQuote(quote: string) {
this.quote = quote;
}
}
export const myState = new MyState();
makeAutoObservable can automatically infer that quote
is an observable and setQuote()
is an action.
Make sure that an initial value is assigned to all state properties before calling makeAutoObservable()
, otherwise the property will not be observable.
This is a MobX limitation since we can’t use the TypeScript configuration "useDefineForClassFields": true
due to conflict with Lit decorators mentioned above.
Note | What is a data store? "The main responsibility of stores is to move logic and state out of your components into a standalone testable unit." - Defining data stores in MobX documentation. |
Using a Store
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import '@vaadin/text-field';
import type { TextField } from '@vaadin/text-field';
import { MobxLitElement } from '@adobe/lit-mobx';
import { myState } from 'Frontend/store/my-state'; 1
@customElement('my-view')
export class MyView extends MobxLitElement { 2
render() {
const { quote } = myState; 3
4
return html`
<p>${quote}</p>
<vaadin-text-field .value="${quote}" @input="${this.onInput}"></vaadin-text-field>
`;
}
onInput(e: InputEvent) {
myState.setQuote((e.target as TextField).value); 5
}
}
Import the store into your view or component.
Make sure that the view or component extends
MobxLitElement
. (In a project generated from Vaadin Start, you may extendView
instead.)Alias one or more state properties from
myState
into local variables for easy referencing.Use state properties in the template.
Update state by calling an action method in the store.
By default, it is not allowed to change the state outside of actions. Read more about actions in the MobX documentation.
Understanding MobX
To be able to effectively use MobX and understand how it works, you should take a look at the official MobX documentation, which is a great resource for learning the basic concepts as well as advanced usage.
External Links and References
MobxLitElement from
lit-mobx
Vaadin Tips video: LitElement state management with MobX in a Vaadin Fusion project
Example project mentioned in the video above: https://github.com/marcushellberg/vaadin-fusion-mobx