Props - аргументи компонента. Батько передає їх як атрибути JSX, дитина отримує одним об'єктом (зазвичай з деструктуризацією):
function Avatar({ user, size = 48 }) {
return <img src={user.avatarUrl} alt={user.name} width={size} height={size} />;
}
<Avatar user={currentUser} size={64} />
Правила props:
- лише для читання - компонент не змінює свої props. Якщо значення має змінюватися, це стан (у батька чи в самому компоненті);
- значення за замовчуванням - у деструктуризації (
size = 48); спрацьовує дляundefined, але не дляnull; - розгортання
<Avatar {...props} />зручне для обгорток, але приховує, що саме передається, - використовувати помірно.
children - вміст між тегами компонента:
function Card({ title, children }) {
return (
<section className="rounded border p-4">
<h2>{title}</h2>
{children}
</section>
);
}
<Card title="Профіль">
<Avatar user={user} />
<p>{user.bio}</p>
</Card>
Композиція замість успадкування. У React не створюють class SpecialCard extends Card. Спеціалізація - через props і вкладення:
- «слоти» - кілька props з JSX:
<Layout sidebar={<Nav />} header={<Header />}>...</Layout>; - спеціалізований компонент рендерить загальний з потрібними props:
function WarningCard(props) { return <Card {...props} tone="warning" />; }; - поведінку перевикористовують через власні хуки, а не базові класи.
Чому це краще: компоненти незалежні, їх легко комбінувати в будь-якому порядку, а зміни в «базовому» компоненті не ламають ієрархію нащадків.
Корисний наслідок children для продуктивності: якщо дорогий компонент передано як children, батько, що змінює свій стан, не перерендерює його - JSX-елемент створено вище й не змінився.
Prop drilling - коли дані передаються через багато рівнів, які їх не використовують. Спершу варто спробувати композицію (передати готовий JSX вниз), а вже потім Context.