Назад
Назад к заметкам
· 4 мин чтения

Что такое MobX и как его использовать

Краткое руководство по использованию MobX в React: основные концепции, подключение, пример списка задач с автосохранением и рекомендации по типичным ошибкам.

reactmobxstate-managementperformance

Когда компонент часто пересчитывается или Redux-хранилище становится избыточным, удобнее использовать MobX. Он описывает состояние декларативно, а реактивность обеспечивает мгновенные и предсказуемые обновления. Далее показано подключение MobX к React-проекту и пример списка задач с автосохранением.


Что такое MobX и как он работает

В ядре MobX три простых понятия: observable, action и reaction (или autorun). Observable-объекты хранят данные, а любые изменения в них автоматически “прокидываются” в компоненты, помеченные как observer. Action-функции группируют изменения, чтобы реактивная система могла отслеживать их как один шаг. Reaction/autorun это “слушатели”, которые вызываются, когда зависимые observable меняются.

КонцептЧто делаетПример
observableДелает данные реактивнымиconst count = observable.box(0);
computedКеширует производные значенияconst total = computed(() => items.reduce((s,i)=>s+i.price,0));
actionГруппирует измененияconst add = action(item => items.push(item));
reaction/autorunРеагирует на измененияautorun(() => console.log(count.get()));

Эти четыре блока позволяют построить полностью реактивный слой без громоздких switch-case в редьюсерах.


Подключение MobX к React через mobx-react-lite

Для современных функций React достаточно установить два пакета:

npm i mobx mobx-react-lite

mobx-react-lite экспортирует хук observer, которым оборачиваем любой функциональный компонент. После этого все наблюдаемые свойства из стора будут автоматически пере-рендериваться.

import { observer } from "mobx-react-lite";
import { useLocalObservable } from "mobx-react-lite";

const Counter = observer(() => {
  const store = useLocalObservable(() => ({
    count: 0,
    inc() {
      this.count++;
    },
  }));

  return (
    <div>
      <p>Текущее значение: {store.count}</p>
      <button onClick={store.inc}>+1</button>
    </div>
  );
});

store.inc объявлена внутри observable-объекта и автоматически превращается в действие (auto-action), если включена опция enforceActions: "observed".


Практический пример: список задач с автосохранением

// taskStore.ts
import { makeAutoObservable, reaction } from "mobx";

class TaskStore {
  tasks: string[] = [];
  constructor() {
    makeAutoObservable(this);
    reaction(
      () => this.tasks.slice(),
      (tasks) => localStorage.setItem("tasks", JSON.stringify(tasks))
    );
  }
  add(task: string) {
    this.tasks.push(task);
  }
  remove(index: number) {
    this.tasks.splice(index, 1);
  }
}

export const taskStore = new TaskStore();
// TaskList.tsx
import { observer } from "mobx-react-lite";
import { taskStore } from "./taskStore";
import { useState } from "react";

const TaskList = observer(() => {
  const [input, setInput] = useState("");
  const addTask = () => {
    if (input.trim()) {
      taskStore.add(input.trim());
      setInput("");
    }
  };
  return (
    <div>
      <h3>Мои задачи</h3>
      <ul>
        {taskStore.tasks.map((t, i) => (
          <li key={i}>
            {t}
            <button onClick={() => taskStore.remove(i)}>✕</button>
          </li>
        ))}
      </ul>
      <input
        value={input}
        onChange={(e) => setInput(e.target.value)}
        placeholder="Новая задача"
      />
      <button onClick={addTask}>Добавить</button>
    </div>
  );
});

export default TaskList;

reaction заменяет привычный useEffect: он срабатывает только при реальном изменении массива задач, а не при каждом рендере. При необходимости список можно виртуализовать, чтобы сохранялась отзывчивость.


Частые ошибки и антипаттерны

  1. Изменять observable напрямую без action приводит к непредсказуемым реакциям. Включите enforceActions: "observed" в makeAutoObservable или в глобальную конфигурацию MobX.
  2. Объединять несколько стора в один огромный объект ухудшает читаемость и усложняет autorun. Разделяйте состояние на небольшие модули (например, uiStore, dataStore).
  3. Частое использование observer каждый observer создает подписку. Оборачивайте только те компоненты, которые действительно зависят от observable.
  4. Не отписываться от reaction/autorun в класс-компонентах и сервисах это обязательный шаг.
  5. Смешивание MobX и Redux без четкого разграничения два подхода могут конфликтовать. Выбирайте один инструмент или используйте MobX только для локального UI-state.

FAQ / чеклист для быстрого старта

  • Как проверить, что объект реактивен? console.log(isObservable(store)) должно вернуть true.
  • Можно ли использовать MobX без React? Да, MobX независим и часто применяется в Node-скриптах.
  • Нужен ли @observable-декоратор? Нет, makeAutoObservable обходит необходимость в декораторах, что удобно в CRA/Next.js.
  • Как отладить цепочку реакций? Включите mobx.trace(true) он выводит в консоль, какие наблюдатели сработали.
  • Стоит ли комбинировать с useMemo? Обычно нет, потому что MobX уже кеширует вычисления через computed. useMemo имеет смысл только для тяжелых функций, не связанных с observable.

MobX удобен, когда нужно добавить реактивный слой в небольшие или средние проекты и синхронизировать состояние с внешними источниками (localStorage, websockets). При работе с React-производительностью такие техники, как мемоизация компонентов и оптимизация рендера, естественно дополняют MobX.

Готов начать?

Выбери удобный способ связи — напиши напрямую или оставь заявку

Написать в Telegram

Отвечу в течение пары часов