Suggest an editImprove this articleRefine the answer for “How does MobX track dependencies?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**MobX automatically tracks dependencies between data (**`observable`**) and computations (**`computed`**,** `autorun`**,** `observer`**)**. When you read an `observable` value somewhere, MobX "remembers" it as a dependency. **Key point:** the next time that value changes, MobX knows exactly who to notify - only those who actually depend on it.Shown above the full answer for quick recall.Answer (EN)Image## In short > **MobX automatically tracks dependencies between data (**`observable`**) and computations (**`computed`**,** `autorun`**,** `observer`**)**. > > When you read an `observable` value 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"): ```javascript 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 ```javascript import { observable, autorun } from 'mobx' const person = observable({ name: 'Tim', age: 25, }) // autorun - a reaction (derivation) autorun(() => { console.log(`Name: ${person.name}`) }) ``` What happens: 1. `autorun` runs → executes its callback. 2. Inside the callback, MobX **notices the read** of `person.name`. 3. MobX registers the dependency: `autorun #1 depends on person.name`. 4. When `person.name` changes, MobX calls `autorun` again. `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: ```javascript 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 ```javascript 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: 1. `fullName` depends on `firstName` and `lastName`; 2. `autorun` depends on `fullName`; 3. The dependency graph: ```javascript firstName → fullName → autorun lastName → fullName → autorun ``` 4. Changing `store.firstName` triggers a recomputation of `fullName`, and only if the value of `fullName` actually changed does `autorun` run again. **No unnecessary reactions**, everything is computed "on demand". --- ## Example 4 - a React component (observer) ```javascript 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: 1. records which `observable`s were read (here, `store.count`); 2. subscribes the component only to those fields; 3. 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 1. An **observable** keeps a list of its subscribers (reactions). 2. A **derivation (computed/autorun/observer)** keeps track of which observables it depends on. 3. When an observable is read, MobX calls `reportObserved()`; when it is written, `reportChanged()`. 4. When an observable changes, MobX notifies all the derivations that were registered. 5. 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**: - `autorun` recomputes only if *its specific dependencies* changed. - `computed` values are cached and recomputed **lazily** (only when needed). - React `observer` components 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*.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.