Комментарии (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
| Аспект | MobX | Redux | Zustand |
|---|---|---|---|
| Boilerplate | Минимум | Много | Среднее |
| Отладка | DevTools | Time-travel | DevTools |
| Кривая обучения | Средняя | Высокая | Низкая |
| Производительность | Отличная | Хорошая | Отличная |
| Immutability | Не требуется | Требуется | Рекомендуется |
| Размер бандла | 30KB | 12KB | 2KB |
Когда использовать MobX
Хорошо подходит для:
- Сложных состояний с множеством зависимостей
- Больших enterprise приложений
- Когда нужна простота написания
- Real-time приложений
Не подходит для:
- Микрофронтендов (сложнее изолировать)
- Когда нужен time-travel debugging
- Очень простых приложений
Заключение
MobX - это мощный инструмент для управления состоянием, который я активно использовал. Отладка MobX довольно простая благодаря DevTools и встроенным функциям трассировки. Главное преимущество - это реактивность: ты пишешь меньше кода, а MobX автоматически отслеживает зависимости и обновляет компоненты только когда необходимо.