Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що робить reaction()?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`reaction()`** - це функція MobX, яка реагує (реактивно) на зміну певних спостережуваних (observable) даних і виконує побічний ефект (side effect), коли вони змінюються. **Ключове:** на відміну від `autorun()`, який виконується щоразу, коли всередині його тіла використовується будь-який observable, `reaction()` відстежує лише результат функції-трекера і викликає ефект тільки тоді, коли цей результат справді змінився.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Що таке `reaction()` > `reaction()` - це функція MobX, > яка **реагує (реактивно)** на зміну **певних спостережуваних (observable)** даних > і виконує **побічний ефект (side effect)**, коли вони змінюються. Можна сказати, що це аналог `useEffect()` з React, але працює **на рівні MobX**, і **без участі React-компонента**. --- ## 1. Базовий синтаксис ```javascript import { observable, reaction } from "mobx" const price = observable.box(100) const quantity = observable.box(2) // реакція: стежимо за зміною total reaction( () => price.get() * quantity.get(), // функція-трекер (що відстежувати) (total, prevTotal) => { // ефект (що робити при зміні) console.log(`Total changed: ${prevTotal} → ${total}`) } ) price.set(120) // Total changed: 200 → 240 quantity.set(3) // Total changed: 240 → 360 ``` MobX: 1. Викликає "трекер" (перша функція), щоб дізнатися залежності, 2. Стежить за ними, 3. Щоразу, коли результат **змінюється**, викликає побічний ефект (друга функція). --- ## 2. У чому відмінність від `autorun()` `autorun()` виконується **щоразу**, коли залежні observable **використовуються в тілі**. `reaction()` - більш **цільова**: вона **відстежує лише те, що повертає перша функція** (selector). | | **autorun()** | **reaction()** | |---|---|---| | Що відстежує | Все, що використовується всередині тіла | Лише результат функції-трекера | | Коли викликається | Щоразу при зміні залежностей | Лише якщо результат справді змінився | | Використовується для | Логів, загальних реакцій | Точного контролю side-ефектів | Тобто `reaction()` - це "тонке налаштування" реактивних побічних ефектів. --- ## 3. Приклад з фільтрацією змін ```javascript import { makeAutoObservable, reaction } from "mobx" class CartStore { items = [] constructor() { makeAutoObservable(this) // стежимо за кількістю товарів reaction( () => this.items.length, (count) => { console.log(`Кількість товарів змінилася: ${count}`) } ) } add(item) { this.items.push(item) } } const cart = new CartStore() cart.add("T-shirt") // → Кількість товарів змінилася: 1 cart.add("Jeans") // → Кількість товарів змінилася: 2 ``` Тут реакція **спрацьовує лише при зміні довжини масиву**, а не при кожній зміні `items`. --- ## 4. Параметри `reaction()` ```javascript reaction( expression, // функція, яка повертає "що відстежувати" effect, // функція, що викликається при зміні options? // опції ) ``` ### Опції: | Опція | Що робить | Приклад | |---|---|---| | `fireImmediately` | запустити ефект одразу при ініціалізації | `{ fireImmediately: true }` | | `equals` | кастомна функція порівняння (типово `!==`) | `{ equals: (a, b) => JSON.stringify(a) === JSON.stringify(b) }` | | `delay` | затримка виклику ефекту (дебаунс) | `{ delay: 300 }` | | `name` | ім'я для дебагу | `{ name: "cartReaction" }` | --- ### Приклад з `fireImmediately` ```javascript reaction( () => store.user, (user) => { console.log("Поточний користувач:", user) }, { fireImmediately: true } ) ``` Виведе користувача одразу при ініціалізації, а потім при кожній зміні `store.user`. --- ## 5. Приклад "побічного ефекту" (API-запит) ```javascript reaction( () => store.searchQuery, async (query) => { if (query.length < 3) return const results = await api.search(query) store.results = results }, { delay: 400 } // debounce ) ``` Це класичний сценарій: **реакція на зміну observable** (наприклад, рядка пошуку), і виконання **асинхронного ефекту** (запит до API). --- ## 6. Відмінність від `computed` | | **computed** | **reaction** | |---|---|---| | Що робить | Обчислює значення | Запускає побічний ефект | | Повертає щось | Так | Ні | | Кешує результат | Так | Ні | | Змінює стан | Ні | Може | | Використовується для | Derived data | Side-effects | `computed` - "чисте" значення, `reaction` - "брудна дія" (ефект). --- ## 7. Приклад у класі ```javascript class AuthStore { user = null constructor() { makeAutoObservable(this) reaction( () => this.user?.isLoggedIn, (isLoggedIn) => { if (isLoggedIn) { console.log("Користувач увійшов у систему") } else { console.log("Користувач вийшов") } }, { fireImmediately: true } ) } } ``` Це дозволяє **реагувати на зміну стану** (наприклад, при логіні / логауті), без логіки всередині UI-компонентів. --- ## 8. Очищення (dispose) `reaction()` повертає функцію, яка **зупиняє спостереження**: ```javascript const dispose = reaction( () => store.count, (count) => console.log("count:", count) ) dispose() // тепер реакція більше не спрацює ``` Це корисно при ручному керуванні життєвим циклом (наприклад, поза React). --- ## 9. Візуально ```javascript [observable] → [reaction → side effect] ``` Приклад: `store.query` → `reaction` → `api.search(query)` --- ## Підсумок > `reaction()` - це реактивний спостерігач, > який стежить за конкретними даними (observable) > і виконує **побічний ефект** при їх зміні. --- ### Формула запам'ятовування: > `reaction(trackFn, effectFn)` > = "Стеж за результатом `trackFn` і викликай `effectFn`, якщо він змінився." --- ### Коли використовувати: Коли потрібно **запускати ефект при зміні observable**, але **не викликати його на кожен ререндер**. Наприклад: - Запити до API при зміні стану; - Збереження даних у `localStorage`; - Логування, трекінг, аналітика; - Реакція на зміну авторизації, фільтрів, маршрутів.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.