Skip to main content
Практика завдань

Композиція проти наслідування в React

Композиція проти Наслідування

React сильно віддає перевагу композиції над наслідуванням. Замість того, щоб розширювати компоненти через ієрархії класів, ви компонуєте їх, комбінуючи менші компоненти разом.


Композиція з дітьми

tsx
// Загальний контейнерний компонент function Card({ children, title }: { children: React.ReactNode; title: string }) { return ( <div className="card"> <h2>{title}</h2> <div className="card-body">{children}</div> </div> ); } // Компонуємо різні картки function App() { return ( <> <Card title="Профіль"> <Avatar /> <UserInfo /> </Card> <Card title="Налаштування"> <SettingsForm /> </Card> </> ); }

Патерн Спеціалізації

Створіть спеціалізовані версії загального компонента:

tsx
// Загальний діалог function Dialog({ title, message, children }: { title: string; message: string; children?: React.ReactNode; }) { return ( <div className="dialog"> <h1>{title}</h1> <p>{message}</p> {children} </div> ); } // Спеціалізовані діалоги через композицію function WelcomeDialog() { return ( <Dialog title="Ласкаво просимо!" message="Дякуємо, що приєдналися до нашої платформи." /> ); } function DeleteConfirmDialog({ onConfirm }: { onConfirm: () => void }) { return ( <Dialog title="Видалити?" message="Цю дію не можна скасувати."> <button onClick={onConfirm}>Так, видалити</button> </Dialog> ); }

Патерн Слотів (Іменована Композиція)

tsx
function Layout({ header, sidebar, content, footer }: { header: React.ReactNode; sidebar: React.ReactNode; content: React.ReactNode; footer: React.ReactNode; }) { return ( <div className="layout"> <header>{header}</header> <aside>{sidebar}</aside> <main>{content}</main> <footer>{footer}</footer> </div> ); } // Використання іменованих слотів <Layout header={<Navbar />} sidebar={<Sidebar />} content={<MainContent />} footer={<Footer />} />

Чому НЕ Наслідування?

tsx
// ❌ Наслідування — НЕ робіть цього в React class Button extends React.Component { /* ... */ } class PrimaryButton extends Button { /* ... */ } class DangerButton extends PrimaryButton { /* ... */ } // Жорстка ієрархія, важко змінювати // ✅ Композиція — РОБІТЬ це замість цього function Button({ variant, children, ...props }: ButtonProps) { return <button className={`btn btn-${variant}`} {...props}>{children}</button>; } <Button variant="primary">Зберегти</Button> <Button variant="danger">Видалити</Button>

Резюме Патернів Композиції

ПатернЯкСценарій використання
childrenПередайте JSX як дітейЗагальні контейнери, обгортки
СпеціалізаціяПопередньо заповніть props загального компонентаСпецифічний діалог, варіанти кнопок
СлотиІменовані props для різних областейМакети, складний UI
Render PropsПередайте функцію як propДинамічна логіка рендерингу
HOCОберніть компонент іншимПерехресні питання

Важливо:

Команда React рекомендує композицію над наслідуванням в усіх випадках. Використовуйте children, іменовані props (слоти) та композицію компонентів для створення гнучких UI. Наслідування створює жорсткі ієрархії, які важко рефакторити — композиція зберігає компоненти незалежними та повторно використовуваними.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?
Практика завдань