Передача пропсів до компонента
Компоненти React використовують пропси для взаємодії між собою. Кожен батьківський компонент може передати деяку інформацію своїм дочірнім компонентам, передаючи їм пропси. Пропси можуть нагадувати вам HTML-атрибути, але ви можете передавати через них будь-яке значення JavaScript, включаючи об’єкти, масиви та функції.
You will learn
- Як передавати пропси до компонента
- Як читати пропси з компонента
- Як встановлювати значення за замовчуванням для пропсів
- Як передавати JSX до компонента
- Як пропси змінюються з часом
Знайомі пропси
Пропси — це інформація, яку ви передаєте до тегу JSX. Наприклад, className
, src
, alt
, width
та height
— деякі з пропсів, які ви можете передати до тегу <img>
:
function Avatar() { return ( <img className="avatar" src="https://i.imgur.com/1bX5QH6.jpg" alt="Лін Ланьїн (Lin Lanying)" width={100} height={100} /> ); } export default function Profile() { return ( <Avatar /> ); }
Пропси, які ви можете передати до тегу <img>
, визначені заздалегідь (ReactDOM відповідає стандарту HTML). Але ви можете передати будь-які пропси до власних компонентів, таких як <Avatar>
, щоб налаштувати їх. Ось як це зробити!
Передача пропсів до компонента
У цьому коді компонент Profile
не передає жодних пропсів до свого дочірнього компонента Avatar
:
export default function Profile() {
return (
<Avatar />
);
}
Ви можете передати деякі пропси до компонента Avatar
у два кроки.
Крок 1: Передайте пропси до дочірнього компонента
Спочатку передайте деякі пропси до Avatar
. Наприклад, давайте передамо два пропси: person
(об’єкт) і size
(число):
export default function Profile() {
return (
<Avatar
person={{ name: 'Лін Ланьїн (Lin Lanying)', imageId: '1bX5QH6' }}
size={100}
/>
);
}
Тепер ви можете читати ці пропси всередині компонента Avatar
.
Крок 2: Читайте пропси всередині дочірнього компонента
Ви можете прочитати ці пропси, перераховуючи їх назви person, size
, розділені комами всередині ({
та })
безпосередньо після function Avatar
. Це дозволяє використовувати їх всередині коду Avatar
як змінні.
function Avatar({ person, size }) {
// person та size доступні тут
}
Додайте трохи логіки до Avatar
, яка використовує пропси person
та size
для рендеру, і готово.
Тепер ви можете налаштувати Avatar
для рендеру багатьма різними способами з різними пропсами. Спробуйте змінити значення!
import { getImageUrl } from './utils.js'; function Avatar({ person, size }) { return ( <img className="avatar" src={getImageUrl(person)} alt={person.name} width={size} height={size} /> ); } export default function Profile() { return ( <div> <Avatar size={100} person={{ name: 'Кацуко Сарухаші (Katsuko Saruhashi)', imageId: 'YfeOqp2' }} /> <Avatar size={80} person={{ name: 'Аклілу Лемма (Aklilu Lemma)', imageId: 'OKS67lh' }} /> <Avatar size={50} person={{ name: 'Лін Ланьїн (Lin Lanying)', imageId: '1bX5QH6' }} /> </div> ); }
Пропси дозволяють вам думати про батьківські та дочірні компоненти незалежно. Наприклад, ви можете змінити проп person
або size
всередині Profile
, не думаючи про те, як Avatar
використовує їх. Аналогічно, ви можете змінити якAvatar
використовує ці пропси, не звертаючи уваги на Profile
.
Уявіть пропси як «ручки регулювання», які ви можете налаштовувати. Вони виконують ту саму роль, що і аргументи для функцій — насправді, пропси є єдиним аргументом вашого компонента! Функції компонентів React приймають один аргумент — об’єкт props
:
function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}
Зазвичай вам не потрібен весь об’єкт props
сам по собі, тому ви розкладаєте його на окремі пропси.
Вказання значення за замовчуванням для пропа
Якщо ви хочете задати пропу значення за замовчуванням, на яке він посилатиметься, якщо не вказано іншого, ви можете зробити це завдяки деструктуризації, поставивши =
та значення за замовчуванням відразу після параметра:
function Avatar({ person, size = 100 }) {
// ...
}
Тепер, якщо <Avatar person={...} />
рендериться без пропу size
, size
буде встановлено на 100
.
Значення за замовчуванням використовується тільки у випадку, якщо проп size
відсутній або якщо ви передаєте size={undefined}
. Але якщо ви передаєте size={null}
або size={0}
, значення за замовчуванням не буде використовуватись.
Передача пропсів за допомогою spread синтаксису JSX
Іноді передача пропсів стає дуже повторюваною:
function Profile({ person, size, isSepia, thickBorder }) {
return (
<div className="card">
<Avatar
person={person}
size={size}
isSepia={isSepia}
thickBorder={thickBorder}
/>
</div>
);
}
Немає нічого поганого в повторюваному коді — він може бути більш зрозумілим. Але іноді ви можете цінувати лаконічність. Деякі компоненти передають всі свої пропси своїм дочірнім компонентам, як це робить Profile
з Avatar
. Оскільки вони не використовують жоден зі своїх пропсів напряму, розумніше буде вжити лаконічний синтаксис “spread”:
function Profile(props) {
return (
<div className="card">
<Avatar {...props} />
</div>
);
}
Це передає всі пропси Profile
до Avatar
без перерахування кожної назви окремо.
Використовуйте синтаксис spread з обережністю. Якщо ви використовуєте його в кожному іншому компоненті, то щось пішло не так. Часто це свідчить про те, що вам слід розбити ваші компоненти та передати дочірні елементи як JSX. Детальніше про це далі!
Передача JSX як children
Вкладення вбудованих тегів браузера є звичайною справою:
<div>
<img />
</div>
Іноді ви захочете вкладати свої власні компоненти так само:
<Card>
<Avatar />
</Card>
Коли ви вкладаєте вміст всередині тегу JSX, батьківський компонент отримує цей вміст у пропі з назвою children
. Наприклад, компонент Card
нижче отримає проп children
зі значенням <Avatar />
і відображатиме його в div-обгортці:
import Avatar from './Avatar.js'; function Card({ children }) { return ( <div className="card"> {children} </div> ); } export default function Profile() { return ( <Card> <Avatar size={100} person={{ name: 'Кацуко Сарухаші (Katsuko Saruhashi)', imageId: 'YfeOqp2' }} /> </Card> ); }
Спробуйте замінити <Avatar>
всередині <Card>
на деякий текст, щоб побачити, як компонент Card
може обгорнути будь-який вкладений вміст. Він не потребує “знати”, що саме рендериться всередині нього. Ви ще побачите цей гнучкий паттерн у багатьох місцях.
Ви можете уявляти компонент з пропом children
як компонент з “отвором”, який може бути “заповнений” батьківськими компонентами довільним JSX. Ви часто будете використовувати проп children
для візуальних обгорток: панелей, сіток і т.д.
Illustrated by Rachel Lee Nabors
Як пропси змінюються з часом
Компонент Clock
, наведений нижче, отримує два пропси від батьківського компонента: color
та time
. (Код батьківського компонента не вказаний, оскільки він використовує стан, до деталей якого ми поки не будемо вдаватись.)
Спробуйте змінити колір у полі вибору нижче:
export default function Clock({ color, time }) { return ( <h1 style={{ color: color }}> {time} </h1> ); }
Цей приклад показує, що компонент може отримувати різні пропси з часом. Пропси не завжди є статичними! Тут проп time
змінюється кожну секунду, а проп color
змінюється, коли ви вибираєте інший колір. Пропси відображають дані компонента в будь-який момент часу, а не лише на початку.
Однак, пропси є незмінними (immutable). Коли компоненту потрібно змінити свої пропси (наприклад, відповідно до взаємодії користувача або нових даних), він повинен «попросити» свій батьківський компонент передати йому інші пропси — новий об’єкт! Його старі пропси будуть відкинуті, і, врешті-решт, рушій JavaScript звільнить пам’ять, яку вони займали.
Не намагайтеся «змінювати пропси». Коли вам потрібно відреагувати на вхідні дані користувача (наприклад, змінювати вибраний колір), вам потрібно «встановити стан», про який ви можете дізнатися у розділі Стан: Пам’ять компонента.
Recap
- Щоб передати пропси, додайте їх до JSX, подібно до атрибутів HTML.
- Щоб прочитати пропси, використовуйте синтаксис деструктуризації
function Avatar({ person, size })
. - Ви можете вказати значення за замовчуванням, наприклад,
size = 100
, яке використовується для відсутніх таundefined
пропсів. - Ви можете передати всі пропси JSX за допомогою
spread
синтаксису<Avatar {...props} />
, але не зловживайте цим! - Вкладений JSX, наприклад
<Card><Avatar /></Card>
, буде виглядати як пропchildren
компонентаCard
. - Пропси в момент часу можуть бути використані тільки для читання: кожен рендер отримує нову версію пропсів.
- Ви не можете змінювати пропси. Для інтерактивності використовуйте стан.
Challenge 1 of 3: Винесіть компонент
Цей компонент Gallery
містить дуже схожу розмітку для двох профілів. Винесіть компонент Profile
з нього, щоб зменшити дублювання. Вам потрібно буде вибрати, які пропси передати йому.
import { getImageUrl } from './utils.js'; export default function Gallery() { return ( <div> <h1>Визначні вчені</h1> <section className="profile"> <h2>Марія Склодовська-Кюрі (Maria Skłodowska-Curie)</h2> <img className="avatar" src={getImageUrl('szV5sdG')} alt="Марія Склодовська-Кюрі (Maria Skłodowska-Curie)" width={70} height={70} /> <ul> <li> <b>Професія: </b> фізик та хімік </li> <li> <b>Нагороди: 4 </b> (Нобелівська премія з фізики, Нобелівська премія з хімії, Медаль Дейві, Медаль Маттеуччі) </li> <li> <b>Відкрито: </b> полоній (хімічний елемент) </li> </ul> </section> <section className="profile"> <h2>Кацуко Сарухаші (Katsuko Saruhashi)</h2> <img className="avatar" src={getImageUrl('YfeOqp2')} alt="Кацуко Сарухаші (Katsuko Saruhashi)" width={70} height={70} /> <ul> <li> <b>Професія: </b> геохімік </li> <li> <b>Нагороди: 2 </b> (Премія Міяке з геохімії, Премія Танака) </li> <li> <b>Відкрито: </b> метод вимірювання вмісту діоксиду карбону в морській воді </li> </ul> </section> </div> ); }