Skip to main content

Як MobX відстежує залежності?

Коротко

MobX автоматично відстежує залежності між даними (observable) і обчисленнями (computed, autorun, observer).

Коли ти десь читаєш observable-значення, MobX "запам'ятовує" це як залежність. При наступній зміні цього значення MobX знає, кого сповістити - лише тих, хто реально від нього залежить.


Основна ідея

MobX будує граф залежностей ("дерево реактивності"):

javascript
observable → derivation (computed, autorun, observer)

observable - джерело даних derivation - все, що читає ці дані reaction - дія, яка запускається при зміні

Щоразу, коли деривація читає observable, MobX реєструє залежність:

"Ця derivation залежить від цього observable".


Приклад 1 - базова механіка

javascript
import { observable, autorun } from 'mobx' const person = observable({ name: 'Tim', age: 25, }) // autorun - реакція (derivation) autorun(() => { console.log(`Name: ${person.name}`) })

Що відбувається:

  1. autorun запускається → виконує свій колбек.
  2. Всередині колбека MobX помічає читання person.name.
  3. MobX реєструє залежність: autorun #1 залежить від person.name.
  4. Коли person.name зміниться, MobX викличе autorun знову.

autorun не буде викликаний, якщо зміниться person.age, тому що воно не використовувалося в колбеку.


Приклад 2 - як MobX "шпигує" за читаннями

MobX обгортає кожен observable-геттер у proxy або getter/setter, який виконує приблизно наступне:

javascript
get name() { registerDependency(this, 'name') // MobX "запам'ятовує", що це поле було прочитане return this._name }

Коли запускається реактивна функція (autorun, computed, observer), MobX тимчасово вмикає "режим запису залежностей". Усі звернення до observable в цей момент реєструються.


Приклад 3 - з 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) })

Що робить MobX:

  1. fullName залежить від firstName і lastName;
  2. autorun залежить від fullName;
  3. Граф залежностей:
javascript
firstName → fullName → autorun lastName → fullName → autorun
  1. Зміна store.firstName викликає перерахунок fullName, і тільки якщо значення fullName реально змінилося, перезапускається autorun.

Жодних зайвих реакцій, все обчислюється "за потребою".


Приклад 4 - React-компонент (observer)

javascript
import { observer } from 'mobx-react-lite' const Counter = observer(({ store }) => ( <div> <p>{store.count}</p> <button onClick={() => store.inc()}>+</button> </div> ))

Коли React рендерить <Counter>, MobX:

  1. фіксує, які observable були прочитані (тут - store.count);
  2. підписує компонент лише на ці поля;
  3. при їх зміні запускає перерендер лише цього компонента.

Тобто кожен observer стає реакцією, а MobX сам реєструє залежності при читанні.


Як MobX реалізує це всередині

  1. Observable зберігає список своїх підписників (реакцій).
  2. Derivation (computed/autorun/observer) зберігає, від яких observable вона залежить.
  3. При читанні observable MobX викликає reportObserved(), при записі - reportChanged().
  4. Коли observable змінюється, MobX сповіщає всі derivation, які були зареєстровані.
  5. Derivation перераховуються лише якщо дійсно зачеплено значення, від якого вони залежать.

Важлива оптимізація

MobX не просто "все перераховує заново" - він робить fine-grained dependency tracking:

  • autorun перерахується лише якщо його конкретні залежності змінилися.
  • computed кешуються і перераховуються ліниво (лише якщо потрібно).
  • React-компоненти observer перерендерюються лише якщо використані observable змінилися.

Підсумок

ЕлементРоль
observableдані, за якими MobX стежить
computedпохідне значення, яке MobX перераховує при змінах
reaction / autorun / observerте, що запускається, коли щось змінилося
dependency graphвнутрішня структура, що їх з'єднує
fine-grained trackingлише реальні залежності викликають реакції

Формула MobX

"Anything that can be derived from the state, should be derived automatically."

Все, що може бути обчислене зі стану, має обчислюватися автоматично.

А MobX робить це, відстежуючи залежності на рівні операцій читання observable.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.