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. However, your application may grow to have many views or a complex UI where the same data needs to be displayed in multiple places, or where there are many dependencies between UI controls. In such situations, it may become difficult to keep the application in a consistent state when the user interacts with it. 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 such as MobX can help to make the application easier to maintain and extend. Here, we focus on an approach to store all shared frontend state in a central MobX state store that acts as the single source of truth for the application state. It’s then easy to display the state data, or anything derived from it, anywhere in the UI, so that the data is automatically updated everywhere it’s displayed whenever the data is updated in the state store.
Using MobX in your Application
Hilla recommends using the MobX library to manage frontend state in your applications.
When using Lit, you need to 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 Hilla project with the Hilla 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 can 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 the 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()
) to update 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 cannot use the TypeScript configuration "useDefineForClassFields": true
due to the conflict with Lit decorators mentioned earlier.
Note
|
Data Store Definition
"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
View
. -
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, the state cannot be changed outside of actions. Read more about actions in the MobX documentation.
Understanding MobX
For information on using MobX effectively and understanding 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 & References
-
MobxLitElement from
lit-mobx
-
Hilla Tips video: LitElement state management with MobX in a Hilla project
-
Example project referenced in the aforementioned video: https://github.com/marcushellberg/vaadin-fusion-mobx