Передача пропсів до компонента
Компоненти 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> ); }
Props дозволяють вам думати про батьківські та дочірні компоненти незалежно. Наприклад, ви можете змінити проп 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 як дітей
Вкладення вбудованих тегів браузера є звичайною справою:
<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 за допомогою синтаксису розширення
<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> ); }