Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Як MobX відстежує залежності?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**MobX автоматично відстежує залежності між даними (**`observable`**) і обчисленнями (**`computed`**,** `autorun`**,** `observer`**)**. Коли ти десь читаєш `observable`-значення, MobX "запам'ятовує" це як залежність. **Ключове:** при наступній зміні цього значення MobX знає, кого сповістити - лише тих, хто реально від нього залежить.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Коротко > **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 ``` 4. Зміна `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*.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.