How does MobX track dependencies?
In short
MobX automatically tracks dependencies between data (
observable) and computations (computed,autorun,observer).When you read an
observablevalue somewhere, MobX "remembers" it as a dependency. The next time that value changes, MobX knows who to notify - only those who actually depend on it.
The core idea
MobX builds a dependency graph (a "reactivity tree"):
observable → derivation (computed, autorun, observer)observable - a source of data derivation - anything that reads that data reaction - an action that runs on change
Every time a derivation reads an observable, MobX registers a dependency:
"This derivation depends on this observable".
Example 1 - basic mechanics
import { observable, autorun } from 'mobx'
const person = observable({
name: 'Tim',
age: 25,
})
// autorun - a reaction (derivation)
autorun(() => {
console.log(`Name: ${person.name}`)
})What happens:
autorunruns → executes its callback.- Inside the callback, MobX notices the read of
person.name. - MobX registers the dependency:
autorun #1 depends on person.name. - When
person.namechanges, MobX callsautorunagain.
autorun will not be called if person.age changes, because it was not used inside the callback.
Example 2 - how MobX "spies" on reads
MobX wraps every observable getter in a proxy or getter/setter that does roughly the following:
get name() {
registerDependency(this, 'name') // MobX "remembers" that this field was read
return this._name
}When a reactive function runs (autorun, computed, observer),
MobX temporarily switches on "dependency-recording mode".
Every access to an observable at that moment gets registered.
Example 3 - with computed
import { makeAutoObservable } from 'mobx'
class Store {
firstName = 'Tim'
lastName = 'Fattore'
constructor() {
makeAutoObservable(this)
}
get fullName() {
return `${this.firstName} ${this.lastName}`
}
}
const store = new Store()
autorun(() => {
console.log(store.fullName)
})What MobX does:
fullNamedepends onfirstNameandlastName;autorundepends onfullName;- The dependency graph:
firstName → fullName → autorun
lastName → fullName → autorun- Changing
store.firstNametriggers a recomputation offullName, and only if the value offullNameactually changed doesautorunrun again.
No unnecessary reactions, everything is computed "on demand".
Example 4 - a React component (observer)
import { observer } from 'mobx-react-lite'
const Counter = observer(({ store }) => (
<div>
<p>{store.count}</p>
<button onClick={() => store.inc()}>+</button>
</div>
))When React renders <Counter>, MobX:
- records which
observables were read (here,store.count); - subscribes the component only to those fields;
- triggers a re-render of only this component when they change.
So every observer becomes a reaction, and MobX itself registers dependencies as they are read.
How MobX implements this internally
- An observable keeps a list of its subscribers (reactions).
- A derivation (computed/autorun/observer) keeps track of which observables it depends on.
- When an observable is read, MobX calls
reportObserved(); when it is written,reportChanged(). - When an observable changes, MobX notifies all the derivations that were registered.
- Derivations are recomputed only if the value they actually depend on was affected.
An important optimization
MobX doesn't just "recompute everything from scratch"; it does fine-grained dependency tracking:
autorunrecomputes only if its specific dependencies changed.computedvalues are cached and recomputed lazily (only when needed).- React
observercomponents re-render only if the observables they used changed.
Summary
| Element | Role |
|---|---|
| observable | data that MobX tracks |
| computed | a derived value that MobX recomputes on changes |
| reaction / autorun / observer | what runs when something changed |
| dependency graph | the internal structure that connects them |
| fine-grained tracking | only real dependencies trigger reactions |
The MobX formula
"Anything that can be derived from the state, should be derived automatically."
Everything that can be computed from the state should be computed automatically.
And MobX does this by tracking dependencies at the level of observable read operations.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.