SRP в React-компонентах
Що таке SRP (у загальному вигляді)
Single Responsibility Principle - принцип єдиної відповідальності.
Формулювання (за Робертом Мартіном, автором SOLID): "У модуля повинна бути одна і тільки одна причина для зміни."
У React цей "модуль" - компонент. Якщо компонент робить занадто багато, то:
- його важко зрозуміти;
- його важко тестувати;
- будь-яка зміна може непередбачувано вплинути на інші частини UI.
SRP у React: просте визначення
React-компонент повинен робити тільки одну річ - і робити її добре.
Тобто:
- Один компонент = одна відповідальність.
- Якщо компонент керує і логікою, і зовнішнім виглядом, і даними, і API - він порушує SRP.
Приклад порушення SRP (поганий код)
function UserProfile() {
const [user, setUser] = useState(null);
useEffect(() => {
fetch('/api/user')
.then(res => res.json())
.then(setUser);
}, []);
const handleDelete = async () => {
await fetch(`/api/user/${user.id}`, { method: 'DELETE' });
setUser(null);
};
if (!user) return <div>Loading...</div>;
return (
<div>
<h1>{user.name}</h1>
<button onClick={handleDelete}>Видалити користувача</button>
</div>
);
}Проблеми:
- Компонент завантажує дані (data fetching),
- Відображає UI,
- Містить бізнес-логіку (видалення),
- Керує станом.
-> Занадто багато відповідальності в одному місці. -> Важко перевикористовувати, тестувати, підтримувати.
Приклад з SRP (правильний підхід)
Розділимо обов'язки:
1. Компонент відповідає за дані:
function useUser() {
const [user, setUser] = useState(null);
useEffect(() => {
fetch('/api/user').then(res => res.json()).then(setUser);
}, []);
const deleteUser = async () => {
await fetch(`/api/user/${user.id}`, { method: 'DELETE' });
setUser(null);
};
return { user, deleteUser };
}2. Компонент відображає дані (UI):
function UserProfileView({ user, onDelete }) {
if (!user) return <div>Loading...</div>;
return (
<div>
<h1>{user.name}</h1>
<button onClick={onDelete}>Видалити користувача</button>
</div>
);
}3. Компонент-композиція (контейнер):
function UserProfile() {
const { user, deleteUser } = useUser();
return <UserProfileView user={user} onDelete={deleteUser} />;
}Тепер:
useUser- відповідає за дані і бізнес-логіку;UserProfileView- відповідає тільки за UI;UserProfile- збирає їх разом.
Переваги SRP у React
| Перевага | Що дає |
|---|---|
| Зрозумілість | Кожен компонент робить щось одне і очевидне |
| Перевикористовуваність | UI-компонент можна використовувати з іншими даними |
| Тестованість | Можна окремо тестувати UI і логіку |
| Підтримуваність | Зміна логіки не ламає розмітку |
| Продуктивність | Простіше оптимізувати окремі частини |
| Розширюваність | Можна додавати нові функції без правок старих компонентів |
Типові категорії відповідальності в React
| Категорія | Приклади компонентів |
|---|---|
| Презентаційні (UI) | кнопки, картки, форми, списки, layout |
| Контейнерні (логіка) | завантаження даних, виклики API, обробка подій |
| Композиційні | збирають UI-компоненти разом |
| Хуки / Логічні блоки | містять бізнес-логіку без UI (useAuth, useCart, useUser) |
Приклад архітектури за SRP
/components
├── ui/
│ ├── Button.tsx ← UI-компонент
│ ├── Card.tsx ← UI-компонент
│ └── UserProfileView.tsx← Відображення
├── containers/
│ └── UserProfile.tsx ← Контейнер
/hooks
└── useUser.ts ← Логіка даних-> Кожен рівень робить тільки свою справу, React-компоненти стають як "чисті функції інтерфейсу".
Коли SRP порушується найчастіше
Типові ситуації:
- Компонент завантажує дані і одразу їх рендерить;
- UI-компонент зберігає локальний state, не пов'язаний з відображенням;
- Один компонент керує і layout'ом, і логікою;
- Надлишкові
useEffectвсередині UI-компонентів.
Підсумок
| Що означає SRP | У React це означає |
|---|---|
| "Одна відповідальність" | Компонент вирішує одну задачу |
| Легко тестувати | Тому що робить щось одне |
| Легко розширювати | Зміна логіки не ламає UI |
| Архітектурно чисто | UI, логіка і дані - окремо |
| Приклад | useUser (логіка) + UserProfileView (UI) + UserProfile (композиція) |
Простими словами:
Компонент React повинен бути як чистий інструмент: одна мета, одна поведінка, одне місце, де щось може зламатися.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.