MobX Core Concepts
Observable State
What: Data that MobX tracks for changes
import { observable, makeObservable } from 'mobx'
class Store {
count = 0
constructor() {
makeObservable(this, {
count: observable
})
}
}
Actions
What: Functions that modify observable state
import { action } from 'mobx'
class Store {
increment = () => {
this.count++
}
constructor() {
makeObservable(this, {
count: observable,
increment: action
})
}
}
Computed Values
What: Derived values that update automatically when dependencies change
import { computed } from 'mobx'
class Store {
get doubleCount() {
return this.count * 2
}
constructor() {
makeObservable(this, {
count: observable,
doubleCount: computed
})
}
}
Reactions
What: Side effects that run when observables change
autorun
Runs immediately and re-runs when dependencies change:
import { autorun } from 'mobx'
autorun(() => {
console.log(`Count is: ${store.count}`)
})
reaction
Runs only when specific data changes:
import { reaction } from 'mobx'
reaction(
() => store.count,
(count) => console.log(count)
)
when
Runs once when condition becomes true:
import { when } from 'mobx'
when(
() => store.count > 10,
() => console.log('Count exceeded 10!')
)
Lit Integration
What: Using MobX with Lit web components
import { LitElement, html } from 'lit'
import { customElement, property } from 'lit/decorators.js'
import { autorun } from 'mobx'
@customElement('counter-element')
class CounterElement extends LitElement {
@property({ type: Number }) count = 0
connectedCallback() {
super.connectedCallback()
this.disposer = autorun(() => {
this.count = store.count
})
}
disconnectedCallback() {
super.disconnectedCallback()
this.disposer?.()
}
render() {
return html`
<div>
<p>Count: ${this.count}</p>
<button @click=${store.increment}>+</button>
</div>
`
}
}
Core Principles
-
Anything that can be derived, should be derived
Use computed values instead of storing derived data -
State should be minimal
Only store what cannot be computed from other state -
Actions modify state
All state modifications should happen in actions
Key Decorators & Functions
Concept | Purpose | Usage |
---|---|---|
observable | Makes data reactive | @observable or observable(obj) |
action | Marks state-modifying functions | @action or action(fn) |
computed | Creates derived values | @computed get value() |
observer | Makes Lit components reactive | Use autorun in lifecycle |
makeObservable | Setup observability in class | In constructor |
runInAction | Execute code as an action | runInAction(() => {}) |
Best Practices
- Always use
makeObservable
in constructors for class-based stores - Keep actions simple – one responsibility per action
- Use
computed
for expensive calculations that depend on observables - Minimize observable surface area – only make necessary data observable
- Use strict mode in development to catch anti-patterns
Mental Model
MobX = Spreadsheet for JavaScript
Concept | Analogy |
---|---|
Observables | Cells with data |
Computed | Formulas that auto-update |
Actions | User inputs that change cells |
Reactions | Side effects when cells change |
Useful Chrome Extensions
PlantUML Diagram
Loading Diagram...