What is a computed value in MobX?
What a computed value is
A computed value (or "computed property") - is a value that automatically recalculates, when the observable data it depends on changes.
In other words:
computed is a "reactive
get" that MobX caches and recalculates only when necessary.
1. A visual example
import { makeAutoObservable } from "mobx"
class TodoStore {
todos = [
{ title: "Buy bread", done: true },
{ title: "Call a friend", done: false },
]
constructor() {
makeAutoObservable(this)
}
// computed
get completedCount() {
return this.todos.filter(t => t.done).length
}
}
const store = new TodoStore()
console.log(store.completedCount) // 1
store.todos[1].done = true
console.log(store.completedCount) // 2MobX tracks by itself which observables are used in completedCount,
and recalculates it only when the relevant fields change (todos[i].done).
2. How this differs from a plain getter
If this were a plain JS getter, it would recalculate on every call, even if nothing changed.
Computed in MobX works differently:
- it remembers (caches) the last value;
- it recalculates only if the dependencies changed.
This makes computed very efficient.
3. How MobX tracks dependencies
MobX builds a dependency graph between observables and computed values. When observable data changes, MobX invalidates only the necessary computed properties.
Roughly like this:
todos.done → completedCount → UIIf todos changed → recalculate completedCount → update the UI.
If something else changed (unrelated to todos) - completedCount is left alone.
4. How to declare computed
There are 2 ways:
Through a getter:
get fullName() {
return `${this.firstName} ${this.lastName}`
}(If makeAutoObservable is used, MobX detects by itself that this is computed.)
Through makeObservable:
import { makeObservable, observable, computed } from "mobx"
class UserStore {
firstName = "Alex"
lastName = "Smith"
constructor() {
makeObservable(this, {
firstName: observable,
lastName: observable,
fullName: computed,
})
}
get fullName() {
return `${this.firstName} ${this.lastName}`
}
}5. Advantages of computed
| Advantage | Description |
|---|---|
| Automatic update | Recalculates when dependencies change |
| Caching | Does not recalculate unnecessarily |
| Immutability | Cannot be changed directly (read-only) |
| Simple declarativeness | Shows "what depends on what" |
| UI optimization | Components re-render only when dependent data changes |
6. Difference from action and observable
| Type | What it does | Changes data? | Updates reactively? |
|---|---|---|---|
| observable | holds state | Yes | Yes |
| action | changes an observable | Yes | No |
| computed | computes derived values | No | Yes |
7. Example with a reactive UI
import { observer } from "mobx-react-lite"
const TodoInfo = observer(({ store }) => (
<div>
<p>Total tasks: {store.todos.length}</p>
<p>Completed: {store.completedCount}</p>
</div>
))The component automatically updates
when todos changes or completedCount recalculates.
8. Caching in action
console.log(store.completedCount) // 2 - computes it
console.log(store.completedCount) // 2 - takes it from cache
store.todos.push({ title: "New", done: false })
console.log(store.completedCount) // 2 - recalculates againMobX caches the result until the observable dependencies change.
9. "computed value" outside classes (a reactive function)
You can create computed values manually:
import { observable, computed } from "mobx"
const price = observable.box(100)
const quantity = observable.box(2)
const total = computed(() => price.get() * quantity.get())
console.log(total.get()) // 200
price.set(120)
console.log(total.get()) // 240Here computed() works like a reactive function,
MobX tracks the dependencies between price, quantity, and total on its own.
SUMMARY
A computed value is a derived value that MobX automatically recalculates when its dependencies change, and caches, so it doesn't do unnecessary work.
A formula to remember it by
Observable → holds data Action → changes data Computed → computes from data Observer (React) → renders data
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.