Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке children у React». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)`children` - це спеціальний проп у React, який автоматично отримує весь JSX, вкладений між тегами компонента. ```jsx function Card({ children, title }) { return ( <div className="card"> <h2>{title}</h2> {children} </div> ); } <Card title="Привіт"> <p>Цей контент стає children</p> </Card> ``` **Ключове:** `children` заповнюється автоматично - React збирає вкладений JSX і передає його як проп без жодних явних дій з твого боку.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**children** - це спеціальний проп у React, який автоматично отримує всі JSX-елементи, вкладені між відкриваючим і закриваючим тегами компонента. ## Теорія ### TL;DR - `children` заповнюється автоматично з вкладеного JSX - передавати його явно не потрібно - Компонент як рамка для картини: рамка - це компонент, картина - це `children` - Використовуй `children`, коли компонент обгортає контент; звичайні пропси - для конкретних іменованих даних - У TypeScript завжди оголошуй `children: React.ReactNode` в інтерфейсі ### Швидкий приклад ```tsx function Card({ children }) { return <div className="card">{children}</div>; } // Все між тегами стає children <Card> <h1>Заголовок</h1> <p>Опис</p> </Card> // Card рендерить обидва елементи всередині div // children = <h1>Заголовок</h1><p>Опис</p> ``` Коли ти вкладаєш JSX між тегами компонента, React збирає це і передає як проп `children` автоматично. Компоненту не потрібно знати, що всередині. Він просто рендерить там, де стоїть `{children}`. ### Як це працює React перетворює JSX на виклики функцій. `<Card><h1>Title</h1></Card>` стає `Card({ children: <h1>Title</h1> })`. Якщо вкладаєш кілька елементів, `children` стає масивоподібним об'єктом. Один елемент - `children` це сам елемент. Кілька - це масив. Ця асиметрія є джерелом поширеної помилки (дивись нижче). ### Коли використовувати Використовуй `children`, коли: - Будуєш layout-обгортки: `Page`, `Container`, `Section` - Створюєш UI-контейнери: `Card`, `Modal`, `Sidebar`, `Drawer` - Завдання компонента - обгорнути контент стилями або поведінкою Пропускай `children`, коли потрібно кілька іменованих слотів. `Dialog` з окремими `header`, `body` і `footer` зручніше описати через явні пропси, а не один проп `children`. ### Типові помилки **Припускати, що children завжди масив:** ```tsx // Падає, якщо передати один елемент function List({ children }) { return <ul>{children.map(item => <li>{item}</li>)}</ul>; } <List><span>Один елемент</span></List> // children - це span, а не масив ``` Виправлення: використовуй `React.Children.toArray()`: ```tsx function List({ children }) { const items = React.Children.toArray(children); return <ul>{items.map((item, i) => <li key={i}>{item}</li>)}</ul>; } ``` **Вважати children рядком:** ```tsx // Працює для тексту, падає для JSX function Button({ children }) { return <button>{children.toUpperCase()}</button>; // Падає якщо children = <Icon /> } ``` `children` може бути рядком, числом, JSX-елементом, масивом або фрагментом. Ніколи не припускай, що це просто рядок. **Забути типи в TypeScript:** ```tsx // TypeScript-помилка - children нема в інтерфейсі interface Props { title: string; } function Card({ title, children }: Props) { // TS скаржиться return <div>{title}{children}</div>; } // Виправлення interface Props { title: string; children: React.ReactNode; } ``` ### Де зустрічається - **Next.js layouts** - `_app.tsx` отримує `children` і обгортає кожну сторінку спільним UI - **React Router** - `<Route>` використовує `children` для рендеру вкладених маршрутів - **Material-UI** - `<Box>`, `<Card>`, `<Dialog>` - всі приймають `children` для гнучкого контенту - **Compound components** - `<Tabs>` і `<TabPanel>` координуються через `children` ### Питання до теми **Q:** Яка різниця між `children` і звичайним пропом, наприклад `content`? **A:** `children` заповнюється автоматично з вкладеного JSX - писати `children={...}` не потрібно. Звичайний проп вимагає явної передачі. `children` - для обгортання контенту, звичайні пропси - для конкретних іменованих даних. **Q:** Чи можна вкласти кілька елементів? **A:** Так. Вкладай скільки завгодно - `children` стане масивоподібним об'єктом з усіма ними. Для безпечного перебору використовуй `React.Children.toArray()`. **Q:** Як типізувати children у TypeScript? **A:** Використовуй `children: React.ReactNode` для максимальної гнучкості. Приймає JSX-елементи, рядки, числа, фрагменти і null. `children: React.ReactElement` - тільки якщо строго потрібен JSX без рядків. **Q:** (Senior) Як додати проп до кожного дочірнього елемента? **A:** `React.Children.map()` разом з `React.cloneElement()`. Завжди перевіряй через `React.isValidElement()`, щоб не зачіпати рядки і числа: ```tsx function WithProp({ children, disabled }) { return React.Children.map(children, child => React.isValidElement(child) ? React.cloneElement(child, { disabled }) : child ); } ``` ## Приклади ### Layout-компонент ```tsx function Page({ children, title }) { return ( <div className="page"> <header> <h1>{title}</h1> </header> <main className="page-content"> {children} </main> <footer>© 2026</footer> </div> ); } export default function App() { return ( <Page title="Дашборд"> <section> <h2>Ласкаво просимо</h2> <p>Твоя статистика тут</p> </section> <section> <h2>Остання активність</h2> </section> </Page> ); } // Обидві секції рендеряться всередині main.page-content // Page не знає, що всередині - просто надає структуру ``` `Page` відповідає за header, footer і розмітку. Контент змінюється без змін у `Page`. У більшості Next.js-проектів саме цей паттерн у кореневому layout - перше місце, де розробники бачать `children` у дії. Ось у чому цінність такого розподілу. ### Фільтрація дочірніх елементів ```tsx function List({ children, filter }) { const items = React.Children.toArray(children); const filtered = filter ? items.filter(item => item.props.active !== false) : items; return ( <ul className="list"> {filtered.map((item, index) => ( <li key={index}>{item}</li> ))} </ul> ); } <List filter={true}> <span active={true}>Елемент 1</span> <span active={false}>Елемент 2</span> <span active={true}>Елемент 3</span> </List> // Рендерить тільки Елемент 1 і Елемент 3 ``` `React.Children.toArray()` нормалізує `children` у звичайний масив незалежно від того, чи це один елемент, масив або фрагмент. Без нього `.filter()` впав би на одному дочірньому елементі.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.