По какому принципу разбиваешь компоненты
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
По какому принципу разбиваешь компоненты?
Разбивка компонентов на части — это один из самых важных навыков в современной фронтенд-разработке. Правильная структуризация компонентов влияет на переиспользуемость кода, читаемость и масштабируемость приложения.
Основной принцип: Single Responsibility Principle (SRP)
Первый и главный принцип — каждый компонент должен отвечать за одну вещь:
// Плохо - компонент делает слишком много
function UserProfile() {
return (
<div>
<h1>User Profile</h1>
<input placeholder="Name" />
<input placeholder="Email" />
<button>Save</button>
<div>User stats</div>
<div>Recent activity</div>
</div>
);
}
// Хорошо - разделены ответственности
function UserProfile({ user }) {
return (
<div>
<UserHeader user={user} />
<UserForm user={user} />
<UserStats user={user} />
<UserActivity user={user} />
</div>
);
}
Принципы разбивки
1. По функциональной площадке (Feature-based) Группируй компоненты по логическим фичам:
components/
auth/
LoginForm.tsx
RegisterForm.tsx
LogoutButton.tsx
comments/
CommentList.tsx
CommentItem.tsx
CommentForm.tsx
profile/
ProfileHeader.tsx
ProfileEdit.tsx
ProfileStats.tsx
Это помогает быстро найти все компоненты, относящиеся к конкретной фиче.
2. По уровню переиспользуемости Разбивай компоненты по уровню абстракции:
components/
ui/ # Базовые UI-компоненты
Button.tsx
Input.tsx
Card.tsx
Modal.tsx
layout/ # Макет страницы
Header.tsx
Footer.tsx
Sidebar.tsx
sections/ # Секции лендинга
HeroSection.tsx
FeaturesSection.tsx
{feature}/ # Компоненты конкретных фич
QuestionList.tsx
QuestionCard.tsx
3. По данным (Smart vs Presentational) Разделяй логику и представление:
// Smart component (контейнер) - работает с данными
export function UserProfileContainer({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]);
return <UserProfilePresentation user={user} />;
}
// Presentational component - только UI
function UserProfilePresentation({ user }) {
return (
<div className="profile">
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
Как я определяю, нужно ли разделить компонент?
Вопросы для себя:
- Размер — компонент > 300 строк? Вероятно, нужна разбивка
- Ответственность — компонент делает 2+ независимых вещи? Раздели
- Переиспользуемость — часть логики нужна в других местах? Выдели в отдельный компонент
- Тестируемость — сложно тестировать компонент целиком? Разбей на части
- Props — много props (> 10)? Возможно, это несколько компонентов
// Признаки, что нужна разбивка
const ComplexComponent = ({
userName,
userEmail,
userAvatar,
userBio,
postTitle,
postContent,
postDate,
comments,
commentCount,
isLoading,
isError,
onSave,
onDelete,
// ... слишком много props
}) => {
// ...
};
Практический пример разбивки
Исходный монолитный компонент:
function ArticleWithComments({ articleId }) {
const [article, setArticle] = useState(null);
const [comments, setComments] = useState([]);
const [newComment, setNewComment] = useState('');
const [loading, setLoading] = useState(true);
useEffect(() => {
// Загрузка статьи
// Загрузка комментариев
}, [articleId]);
// Слишком много логики...
}
После разбивки:
// Контейнер управляет данными
function ArticleWithComments({ articleId }) {
const { article, loading } = useArticle(articleId);
const { comments, addComment } = useComments(articleId);
return (
<>
<ArticleView article={article} />
<CommentsSection comments={comments} onAdd={addComment} />
</>
);
}
// Компоненты только отображают
function ArticleView({ article }) {
return <article>{/* UI */}</article>;
}
function CommentsSection({ comments, onAdd }) {
return <section>{/* UI */}</section>;
}
Правило большого пальца (Rule of Three)
Если код повторяется 3 раза — выдели в компонент:
- 1 раз: OK, не выделяй
- 2 раза: можно выделить для читаемости
- 3+ раза: ОБЯЗАТЕЛЬНО выдели в компонент
Антипаттерны, которых избегаю
Слишком глубокая вложенность:
// Плохо
<UserContainer>
<UserWrapper>
<UserInnerWrapper>
<UserContent />
</UserInnerWrapper>
</UserWrapper>
</UserContainer>
Компонент-свалка:
// Плохо - компонент User.tsx делает всё
// использовать User everywhere
// вместо специализированных компонентов
Props drilling (передача props на много уровней вниз):
// Плохо
<Parent user={user}>
<Child user={user}>
<GrandChild user={user}>
{user.name}
</GrandChild>
</Child>
</Parent>
// Хорошо - использовать Context или hooks
Мой процесс разбивки
- Пишу весь функционал в одном компоненте
- Определяю независимые части (по функциям, по UI блокам)
- Выделяю частые повторения в отдельные компоненты
- Разделяю логику от представления (custom hooks)
- Тестирую каждый компонент отдельно
- Рефакторю для улучшения читаемости
Заключение
Правильная разбивка компонентов — это баланс между гибкостью и простотой. Следуй принципам SRP и SOLID, и твой код будет легче поддерживать, тестировать и расширять. Помни: лучше иметь много маленьких компонентов, чем несколько огромных.