Зачем нужен State Manager для вынесения бизнес-логики?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
State Manager для вынесения бизнес-логики
State Manager (менеджер состояния) — это инструмент для централизованного управления состоянием приложения и отделения бизнес-логики от компонентов представления. Это критически важный паттерн в масштабируемых приложениях.
Проблема без State Manager
Без State Manager'а бизнес-логика размазана по компонентам:
// Плохо: логика в компоненте
function UserProfile() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const fetchUser = async (id) => {
setLoading(true);
try {
const response = await fetch(`/api/users/${id}`);
const data = await response.json();
setUser(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
const updateUser = async (updatedData) => {
setLoading(true);
try {
const response = await fetch(`/api/users/${user.id}`, {
method: "PUT",
body: JSON.stringify(updatedData)
});
const updated = await response.json();
setUser(updated);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchUser(userId);
}, [userId]);
return (
<div>
{loading && <p>Loading...</p>}
{error && <p>Error: {error}</p>}
{user && <p>{user.name}</p>}
</div>
);
}
Проблемы:
- Логика размазана в компоненте
- Сложно переиспользовать эту логику в других компонентах
- Сложно тестировать
- Компонент отвечает за слишком многое
Решение: State Manager
State Manager выносит логику из компонентов:
// 1. Создаём хранилище состояния
const useUserStore = create((set) => ({
user: null,
loading: false,
error: null,
// Бизнес-логика
fetchUser: async (id) => {
set({ loading: true, error: null });
try {
const response = await fetch(`/api/users/${id}`);
const data = await response.json();
set({ user: data });
} catch (err) {
set({ error: err.message });
} finally {
set({ loading: false });
}
},
updateUser: async (updatedData) => {
set({ loading: true, error: null });
try {
const response = await fetch(`/api/users/${user.id}`, {
method: "PUT",
body: JSON.stringify(updatedData)
});
const updated = await response.json();
set({ user: updated });
} catch (err) {
set({ error: err.message });
} finally {
set({ loading: false });
}
}
}));
// 2. Компонент становится простым и чистым
function UserProfile({ userId }) {
const { user, loading, error, fetchUser } = useUserStore();
useEffect(() => {
fetchUser(userId);
}, [userId, fetchUser]);
return (
<div>
{loading && <p>Loading...</p>}
{error && <p>Error: {error}</p>}
{user && <p>{user.name}</p>}
</div>
);
}
Основные преимущества State Manager
1. Разделение ответственности (Separation of Concerns)
Без State Manager:
// Компонент отвечает за всё
function Component() {
const [state, setState] = useState(...);
const [loading, setLoading] = useState(...);
const [error, setError] = useState(...);
const handleClick = async () => { /* логика */ };
const validate = () => { /* логика */ };
const transform = () => { /* логика */ };
return <div>...</div>; // Представление
}
С State Manager:
// Хранилище: бизнес-логика
const store = {
state: { /* данные */ },
fetchData: async () => { /* логика */ },
validate: () => { /* логика */ },
transform: () => { /* логика */ }
};
// Компонент: только представление
function Component() {
const { state, fetchData } = useStore();
return <div>...</div>;
}
2. Переиспользование логики
// Одна логика используется во многих компонентах
function UserProfile() {
const { user, fetchUser } = useUserStore();
// ...
}
function UserCard() {
const { user, fetchUser } = useUserStore();
// ...
}
function UserList() {
const { users, fetchUsers } = useUserStore();
// ...
}
3. Тестируемость
// Легко тестировать логику отдельно
import { renderHook, act } from '@testing-library/react';
import { useUserStore } from './store';
test('fetchUser должен загружать данные', async () => {
const { result } = renderHook(() => useUserStore());
act(() => {
result.current.fetchUser(1);
});
// Логика в хранилище — полностью изолирована
expect(result.current.user).toBeDefined();
});
4. Производительность
State Manager'ы оптимизируют re-renders, подписывая компоненты только на нужные части состояния:
// Zustand автоматически оптимизирует подписки
function UserName() {
const user = useUserStore(state => state.user); // Подписка только на user
}
function LoadingIndicator() {
const loading = useUserStore(state => state.loading); // Подписка только на loading
}
// Когда меняется loading, UserName не re-renderится
5. Отладка и DevTools
State Manager'ы часто имеют DevTools для отладки:
// Zustand
const useUserStore = create(
devtools(persistMiddleware(store))
);
// Redux DevTools
// Можно видеть историю всех действий и состояния
Популярные State Manager'ы
| Инструмент | Плюсы | Минусы |
|---|---|---|
| Redux | Мощный, большое сообщество | Много boilerplate |
| Zustand | Простой, лёгкий | Меньше функционала |
| Recoil | Гибкий, от Facebook | Нестабильный |
| TanStack Query | Для API данных | Не универсален |
| Context API | Встроена в React | Часто недостаточно |
Когда использовать State Manager
Используй State Manager, если:
- Логика сложная и повторяется
- Состояние нужно в разных компонентах
- Нужна отладка и логирование
- Приложение среднее или большое
Не нужен State Manager, если:
- Приложение маленькое
- Состояние используется в одном компоненте
- Логика простая
Вывод
State Manager — это критический инструмент для отделения бизнес-логики от представления. Это делает код более чистым, тестируемым и поддерживаемым. В современной разработке React это практически обязательный паттерн для любого приложения среднего размера и больше.