Suggest an editImprove this articleRefine the answer for “What does reaction() do?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`reaction()`** is a MobX function that reacts to changes in specific observable data and runs a side effect when that data changes. **Key point:** unlike `autorun()`, which runs every time any observable used inside its body changes, `reaction()` tracks only the tracker function's result and calls the effect only when that result actually changed.Shown above the full answer for quick recall.Answer (EN)Image## What is `reaction()` > `reaction()` is a MobX function > that **reacts (reactively)** to a change in **specific observable** data > and runs a **side effect** when it changes. You could call it an analog of React's `useEffect()`, but it works **at the MobX level**, **without any React component involved**. --- ## 1. Basic syntax ```javascript import { observable, reaction } from "mobx" const price = observable.box(100) const quantity = observable.box(2) // reaction: watch for a change in total reaction( () => price.get() * quantity.get(), // tracker function (what to watch) (total, prevTotal) => { // effect (what to do on change) console.log(`Total changed: ${prevTotal} → ${total}`) } ) price.set(120) // Total changed: 200 → 240 quantity.set(3) // Total changed: 240 → 360 ``` MobX: 1. Calls the "tracker" (the first function) to figure out the dependencies, 2. Watches them, 3. Every time the result **changes**, it calls the side effect (the second function). --- ## 2. How it differs from `autorun()` `autorun()` runs **every time** any dependent observable **used inside its body** changes. `reaction()` is more **targeted**: it **tracks only what the first function** (the selector) returns. | | **autorun()** | **reaction()** | |---|---|---| | What it tracks | Everything used inside the body | Only the tracker function's result | | When it's called | Every time a dependency changes | Only if the result actually changed | | Used for | Logging, general reactions | Precise control over side effects | In other words, `reaction()` is "fine-tuned" reactive side effects. --- ## 3. Example filtering out changes ```javascript import { makeAutoObservable, reaction } from "mobx" class CartStore { items = [] constructor() { makeAutoObservable(this) // watch the number of items reaction( () => this.items.length, (count) => { console.log(`Item count changed: ${count}`) } ) } add(item) { this.items.push(item) } } const cart = new CartStore() cart.add("T-shirt") // → Item count changed: 1 cart.add("Jeans") // → Item count changed: 2 ``` Here the reaction **fires only when the array's length changes**, not on every change to `items`. --- ## 4. `reaction()` parameters ```javascript reaction( expression, // a function that returns "what to track" effect, // a function called on change options? // options ) ``` ### Options: | Option | What it does | Example | |---|---|---| | `fireImmediately` | run the effect immediately on initialization | `{ fireImmediately: true }` | | `equals` | a custom comparison function (default `!==`) | `{ equals: (a, b) => JSON.stringify(a) === JSON.stringify(b) }` | | `delay` | delay before calling the effect (debounce) | `{ delay: 300 }` | | `name` | a name for debugging | `{ name: "cartReaction" }` | --- ### Example with `fireImmediately` ```javascript reaction( () => store.user, (user) => { console.log("Current user:", user) }, { fireImmediately: true } ) ``` Logs the user right on initialization, then on every change to `store.user`. --- ## 5. A "side effect" example (an API request) ```javascript reaction( () => store.searchQuery, async (query) => { if (query.length < 3) return const results = await api.search(query) store.results = results }, { delay: 400 } // debounce ) ``` This is a classic scenario: **reacting to an observable change** (e.g. a search string), and running an **asynchronous effect** (an API request). --- ## 6. Difference from `computed` | | **computed** | **reaction** | |---|---|---| | What it does | Computes a value | Triggers a side effect | | Returns something | Yes | No | | Caches the result | Yes | No | | Changes state | No | Can | | Used for | Derived data | Side effects | `computed` is a "pure" value, `reaction` is a "dirty action" (an effect). --- ## 7. Example in a class ```javascript class AuthStore { user = null constructor() { makeAutoObservable(this) reaction( () => this.user?.isLoggedIn, (isLoggedIn) => { if (isLoggedIn) { console.log("User logged in") } else { console.log("User logged out") } }, { fireImmediately: true } ) } } ``` This lets you **react to a state change** (e.g. on login / logout) without logic inside UI components. --- ## 8. Cleanup (dispose) `reaction()` returns a function that **stops the observation**: ```javascript const dispose = reaction( () => store.count, (count) => console.log("count:", count) ) dispose() // the reaction will no longer fire ``` This is useful for manual lifecycle management (e.g. outside React). --- ## 9. Visually ```javascript [observable] → [reaction → side effect] ``` Example: `store.query` → `reaction` → `api.search(query)` --- ## Summary > `reaction()` is a reactive observer > that watches specific data (an observable) > and runs a **side effect** when it changes. --- ### A way to remember it: > `reaction(trackFn, effectFn)` > = "Watch the result of `trackFn` and call `effectFn` if it changed." --- ### When to use it: When you need to **trigger an effect on an observable change**, but **not call it on every re-render**. For example: - API requests when state changes; - Saving data to `localStorage`; - Logging, tracking, analytics; - Reacting to changes in authorization, filters, routes.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.