← Назад к вопросам

Дебажил ли MobX state

2.0 Middle🔥 181 комментариев
#State Management

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Работа с MobX и отладка состояния

Да, я работал с MobX state, и это очень интересный подход к управлению состоянием, который кардинально отличается от Redux или Zustand.

Что такое MobX

MobX - это реактивная библиотека управления состоянием, которая основана на:

  • Автоматическом отслеживании зависимостей (reactive tracking)
  • Минимальном boilerplate коде
  • Прямых мутациях состояния (не требуется immutability)
// MobX в действии - просто и понятно
import { makeAutoObservable } from 'mobx';

class CounterStore {
  count = 0;
  
  constructor() {
    // Делает все методы и поля observable/actions
    makeAutoObservable(this);
  }
  
  increment() {
    this.count++; // Просто мутируем! MobX отследит это
  }
  
  get doubled() {
    return this.count * 2; // Автоматически перевычисляется
  }
}

const store = new CounterStore();

Отличие от Redux

// Redux - много boilerplate
const counterReducer = (state = 0, action) => {
  switch(action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
};

const incrementAction = () => ({ type: 'INCREMENT' });

// MobX - минималистично
class CounterStore {
  count = 0;
  
  increment() {
    this.count++;
  }
}

Отладка MobX state

1. MobX DevTools

// Установить: npm install mobx-react-devtools
import { useLocalObservable } from 'mobx-react-lite';
import { spy } from 'mobx';

// Следим за всеми изменениями
spy((event) => {
  if (event.type === 'action') {
    console.log(`Action: ${event.name}`, event);
  }
  if (event.type === 'reaction') {
    console.log('Reaction произошла:', event);
  }
});

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

2. Трассировка реактивности

import { trace } from 'mobx';

class UserStore {
  users = [];
  
  constructor() {
    makeAutoObservable(this);
  }
  
  get activeUsers() {
    // Трассируем, почему этот computed перевычислился
    trace();
    return this.users.filter(u => u.active);
  }
  
  addUser(user) {
    this.users.push(user);
  }
}

const store = new UserStore();
console.log(store.activeUsers); // Выведет trace в консоль
store.addUser({ name: 'John', active: true });
console.log(store.activeUsers); // Покажет, почему перевычислилось

3. Loggers и мониторинг

import { spy, configure } from 'mobx';

// Настраиваем MobX для логирования
configure({
  enforceActions: 'always', // Все мутации только в actions
  computedRequiresReaction: true, // Warn на неиспользуемые computed
});

// Логируем все действия
spy((event) => {
  switch(event.type) {
    case 'action':
      console.log(`[MobX Action] ${event.name}`);
      break;
    case 'reaction':
      console.log(`[MobX Reaction] Запущена`);
      break;
    case 'observable':
      console.log(`[MobX Observable] ${event.name} = ${event.newValue}`);
      break;
  }
});

Практический пример: Store с отладкой

import { makeAutoObservable, runInAction } from 'mobx';
import { observer } from 'mobx-react-lite';

class PostStore {
  posts = [];
  isLoading = false;
  error = null;
  
  constructor() {
    makeAutoObservable(this, {
      // Можно явно отметить actions
      fetchPosts: true, // это action
      sortByDate: true,
    });
  }
  
  async fetchPosts() {
    console.log('[MobX Debug] Начинаем загрузку постов');
    this.isLoading = true;
    this.error = null;
    
    try {
      const response = await fetch('/api/posts');
      const data = await response.json();
      
      // runInAction гарантирует, что это выполнится как action
      runInAction(() => {
        this.posts = data;
        this.isLoading = false;
        console.log(`[MobX Debug] Загружено ${data.length} постов`);
      });
    } catch (err) {
      runInAction(() => {
        this.error = err.message;
        this.isLoading = false;
        console.error('[MobX Error]', err);
      });
    }
  }
  
  sortByDate() {
    console.log('[MobX Debug] Сортируем посты по дате');
    this.posts.sort((a, b) => new Date(b.date) - new Date(a.date));
  }
  
  // Computed свойство - автоматически перевычисляется
  get recentPosts() {
    console.log('[MobX Debug] Вычисляем recentPosts');
    return this.posts.slice(0, 5);
  }
  
  get totalPosts() {
    return this.posts.length;
  }
}

// React компонент с MobX
const PostList = observer(() => {
  const store = React.useContext(StoreContext);
  
  React.useEffect(() => {
    store.fetchPosts();
  }, [store]);
  
  if (store.isLoading) return <div>Загружаю...</div>;
  if (store.error) return <div>Ошибка: {store.error}</div>;
  
  return (
    <div>
      <h2>Всего постов: {store.totalPosts}</h2>
      <button onClick={() => store.sortByDate()}>Сортировать</button>
      <ul>
        {store.recentPosts.map(post => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
});

Отладка утечек памяти в MobX

import { whenWithTimeout } from 'mobx';

// Проверяем, что реакция заканчивается за разумное время
whenWithTimeout(
  () => store.isDataLoaded === true,
  () => console.log('Данные загружены'),
  5000, // Timeout 5 сек
  () => console.warn('Timeout! Данные так и не загружились')
);

// Отслеживаем неиспользуемые computed
store.dispose?.(); // Если забыли очистить

Сравнение подходов: MobX vs Redux vs Zustand

АспектMobXReduxZustand
BoilerplateМинимумМногоСреднее
ОтладкаDevToolsTime-travelDevTools
Кривая обученияСредняяВысокаяНизкая
ПроизводительностьОтличнаяХорошаяОтличная
ImmutabilityНе требуетсяТребуетсяРекомендуется
Размер бандла30KB12KB2KB

Когда использовать MobX

Хорошо подходит для:

  • Сложных состояний с множеством зависимостей
  • Больших enterprise приложений
  • Когда нужна простота написания
  • Real-time приложений

Не подходит для:

  • Микрофронтендов (сложнее изолировать)
  • Когда нужен time-travel debugging
  • Очень простых приложений

Заключение

MobX - это мощный инструмент для управления состоянием, который я активно использовал. Отладка MobX довольно простая благодаря DevTools и встроенным функциям трассировки. Главное преимущество - это реактивность: ты пишешь меньше кода, а MobX автоматически отслеживает зависимости и обновляет компоненты только когда необходимо.

Дебажил ли MobX state | PrepBro