Пошук уроків, статей та іншого контенту
Використаєте children для створення компонентів-контейнерів і побудови вкладених інтерфейсів без жорсткої прив’язки до вмісту.
childrenchildren — це спеціальний проп, у якому React передає вміст, розміщений між відкривальним і закривальним тегами компонента.
<Card>
<h2>Заголовок</h2>
<p>Текст картки</p>
</Card>У цьому прикладі все між <Card> і </Card> буде доступне всередині компонента через children.
Компонент може відповідати за контейнер, стилі або структуру, а його вміст передається ззовні:
function Card({ children }) {
return <article className="card">{children}</article>;
}Такий підхід називається композицією компонентів. Він дає змогу створювати універсальні компоненти без жорстко заданого внутрішнього вмісту.
childrenfunction Panel({ children }) {
return (
<section className="panel">
{children}
</section>
);
}
function App() {
return (
<Panel>
<h1>Профіль користувача</h1>
<p>Цей вміст передано до Panel через children.</p>
</Panel>
);
}React фактично передає компоненту такі пропси:
{
children: [
<h1>Профіль користувача</h1>,
<p>Цей вміст передано до Panel через children.</p>
]
}Якщо всередині компонента є лише один дочірній елемент, children буде цим елементом. Якщо елементів декілька, React може представити їх як набір дочірніх значень.
Для компонента не потрібно знати, що саме буде передано в children. Він лише визначає, де цей вміст відобразити.
Компонент-контейнер зазвичай відповідає за спільну структуру або оформлення:
function Container({ children }) {
return (
<div
style={{
maxWidth: 720,
margin: "0 auto",
padding: 24
}}
>
{children}
</div>
);
}Тепер один і той самий контейнер можна використовувати для різного вмісту:
function App() {
return (
<Container>
<h1>Головна сторінка</h1>
<p>Вміст першої сторінки.</p>
</Container>
);
}function SettingsPage() {
return (
<Container>
<h1>Налаштування</h1>
<button>Зберегти</button>
</Container>
);
}Container не залежить від конкретної сторінки. Він надає лише спільний зовнішній каркас.
У наступному прикладі:
Page створює загальну структуру сторінки;
Header відображає верхню частину;
Card створює універсальну картку;
children дає змогу передавати довільний вміст;
компоненти комбінуються у вкладену структуру.
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
const styles = {
page: {
minHeight: "100vh",
backgroundColor: "#f3f4f6",
fontFamily: "Arial, sans-serif"
},
header: {
padding: "20px 32px",
backgroundColor: "#111827",
color: "white"
},
content: {
maxWidth: 800,
margin: "0 auto",
padding: 32
},
card: {
padding: 24,
marginBottom: 16,
backgroundColor: "white",
borderRadius: 12,
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.08)"
},
button: {
padding: "10px 16px",
border: 0,
borderRadius: 8,
backgroundColor: "#2563eb",
color: "white",
cursor: "pointer"
}
};
function Page({ children }) {
return (
<div style={styles.page}>
{children}
</div>
);
}
function Header({ children }) {
return (
<header style={styles.header}>
{children}
</header>
);
}
function Content({ children }) {
return (
<main style={styles.content}>
{children}
</main>
);
}
function Card({ children }) {
return (
<section style={styles.card}>
{children}
</section>
);
}
function App() {
return (
<Page>
<Header>
<h1>Панель керування</h1>
</Header>
<Content>
<Card>
<h2>Вітаємо!</h2>
<p>
Цей текст передано до Card через спеціальний проп children.
</p>
</Card>
<Card>
<h2>Швидкі дії</h2>
<button
style={styles.button}
onClick={() => alert("Дію виконано")}
>
Виконати дію
</button>
</Card>
</Content>
</Page>
);
}
createRoot(document.getElementById("root")).render(
<StrictMode>
<App />
</StrictMode>
);Структура інтерфейсу в App описує вкладеність:
Page
├── Header
│ └── h1
└── Content
├── Card
│ ├── h2
│ └── p
└── Card
├── h2
└── buttonКожен контейнер відповідає за свою частину структури, але не контролює внутрішній вміст дочірніх компонентів.
Компоненти можна вкладати один в один на будь-яку глибину:
function Page({ children }) {
return <div className="page">{children}</div>;
}
function Sidebar({ children }) {
return <aside className="sidebar">{children}</aside>;
}
function Navigation({ children }) {
return <nav className="navigation">{children}</nav>;
}
function App() {
return (
<Page>
<Sidebar>
<Navigation>
<a href="/dashboard">Панель керування</a>
<a href="/settings">Налаштування</a>
</Navigation>
</Sidebar>
</Page>
);
}Sidebar не має знати, що всередині буде Navigation. Так само Page не має знати, що одним із його дочірніх елементів буде бічна панель.
Це зменшує зв’язаність компонентів: кожен компонент знає лише про власну відповідальність.
children разом з іншими пропсамиchildren не замінює звичайні пропси. Часто компонент отримує налаштування через звичайні пропси, а вміст — через children.
function Alert({ type, children }) {
const backgroundColor = type === "error" ? "#fee2e2" : "#dcfce7";
return (
<div
style={{
padding: 16,
marginBottom: 12,
backgroundColor,
borderRadius: 8
}}
>
{children}
</div>
);
}
function App() {
return (
<>
<Alert type="success">
<strong>Успішно!</strong>
<p>Дані збережено.</p>
</Alert>
<Alert type="error">
<strong>Помилка!</strong>
<p>Не вдалося виконати операцію.</p>
</Alert>
</>
);
}У цьому прикладі:
type визначає поведінку або оформлення компонента;
children визначає його внутрішній вміст.
Так Alert можна використовувати для різних повідомлень, не додаючи окремі пропси на кшталт title і message для кожного можливого випадку.
Іноді компонент має кілька окремих областей для вмісту. У такому разі можна передати дочірні елементи через власні пропси.
function Dialog({ title, actions, children }) {
return (
<section className="dialog">
<header className="dialog__header">
<h2>{title}</h2>
</header>
<div className="dialog__body">
{children}
</div>
<footer className="dialog__actions">
{actions}
</footer>
</section>
);
}
function App() {
return (
<Dialog
title="Видалити файл?"
actions={
<>
<button>Скасувати</button>
<button>Видалити</button>
</>
}
>
<p>Цю дію неможливо скасувати.</p>
</Dialog>
);
}Тут:
children — основний вміст діалогового вікна;
title — заголовок;
actions — окрема область із кнопками.
Це також композиція, але з кількома визначеними «слотами». Такий підхід корисний, коли компонент має фіксовану структуру з кількома місцями для вставлення вмісту.
childrenchildren може бути відсутнім або мати значення, яке не потрібно показувати. Наприклад, контейнер може додавати внутрішній відступ лише тоді, коли в ньому є вміст.
function Box({ children }) {
return (
<div
style={{
border: "1px solid #d1d5db",
borderRadius: 8,
padding: children ? 16 : 0
}}
>
{children}
</div>
);
}
function App() {
return (
<>
<Box>
<p>У контейнера є дочірній вміст.</p>
</Box>
<Box />
</>
);
}Для простих випадків перевірка children підходить. Проте значення children може бути рядком, числом, елементом, масивом елементів або null, тому не варто без потреби припускати, що це завжди один React-елемент.
Композиція через children добре підходить, коли:
компонент відповідає за контейнер або зовнішню структуру;
внутрішній вміст може бути різним;
потрібно повторно використовувати однакове оформлення;
компонент не повинен знати деталі вмісту;
потрібно будувати вкладені інтерфейси з незалежних частин.
Наприклад, замість компонента, який жорстко містить заголовок, текст і кнопку:
function FixedCard() {
return (
<article>
<h2>Заголовок</h2>
<p>Текст</p>
<button>Дія</button>
</article>
);
}можна створити універсальний контейнер:
function Card({ children }) {
return <article className="card">{children}</article>;
}І передавати конкретний вміст під час використання:
<Card>
<h2>Профіль</h2>
<p>Особисті дані користувача.</p>
</Card>
<Card>
<h2>Замовлення</h2>
<button>Переглянути</button>
</Card>children у параметрах компонентаfunction Card() {
return <article>{children}</article>;
}У цьому випадку children не визначений. Його потрібно отримати з пропсів:
function Card({ children }) {
return <article>{children}</article>;
}Або через об’єкт props:
function Card(props) {
return <article>{props.children}</article>;
}childrenfunction Card({ children }) {
children = <p>Інший текст</p>;
return <article>{children}</article>;
}Так компонент ігнорує вміст, переданий батьківським компонентом. Зазвичай children потрібно лише відобразити або розмістити у визначеній області.
function Card({ title, text, buttonLabel }) {
return (
<article>
<h2>{title}</h2>
<p>{text}</p>
<button>{buttonLabel}</button>
</article>
);
}Такий компонент зручний для дуже конкретного сценарію, але швидко стає обмеженим. Якщо вміст картки може відрізнятися, краще використати children:
function Card({ children }) {
return <article>{children}</article>;
}children як функціїУ звичайному випадку children — це значення, яке потрібно відрендерити:
function Panel({ children }) {
return <section>{children}</section>;
}Не можна викликати його як функцію:
function Panel({ children }) {
return <section>{children()}</section>;
}Такий запис працює лише для окремого патерну, коли батьківський компонент навмисно передає функцію як children. Для звичайної композиції він не потрібен.
children містить вміст між відкривальним і закривальним тегами компонента.
Через children можна створювати універсальні компоненти-контейнери.
Вміст контейнера визначається під час використання компонента, а не всередині його реалізації.
Композиція дає змогу будувати складні інтерфейси з незалежних вкладених компонентів.
children можна поєднувати зі звичайними пропсами.
Для кількох окремих областей можна використовувати додаткові пропси, наприклад header, actions або footer.
Композиція зменшує жорстку прив’язку між контейнером і його вмістом.