| title | Написання UI |
|---|
React — це JavaScript-бібліотека для рендерингу інтерфейсів користувача (далі — UI). UI складається з невеликих елементів, як кнопки, текст і зображення. React дозволяє об'єднувати їх у повторно використовувані компоненти з можливістю вкладення. Від вебсайтів до застосунків для телефону — незалежно від платформи все на екрані можна розбити на компоненти. У цьому розділі ви навчитеся створювати, налаштовувати та відображати залежно від умов компоненти React.
- Як написати ваш перший React-компонент
- Коли і як створювати файли з багатьма компонентами
- Як додати розмітку до JavaScript за допомогою JSX
- Як використовувати фігурні дужки у JSX, щоб отримати доступ до функціональності JavaScript із ваших компонентів
- Як налаштовувати компоненти за допомогою пропсів
- Як умовно рендерити компоненти
- Як рендерити безліч компонентів одночасно
- Як уникнути заплутаних помилок за допомогою "чистих" компонентів
- Чому корисно розуміти ваш UI як дерево
React-застосунки створені з ізольованих частин UI, які називаються компонентами. Компонент React — це функція JavaScript, до якої можна додати розмітку. Компоненти можуть бути маленькими, як кнопка, або великими, як ціла сторінка. Ось компонент Gallery, який рендерить три компоненти Profile:
function Profile() {
return (
<img
src="https://i.imgur.com/MK3eW3As.jpg"
alt="Кетрін Джонсон (Katherine Johnson)"
/>
);
}
export default function Gallery() {
return (
<section>
<h1>Видатні вчені</h1>
<Profile />
<Profile />
<Profile />
</section>
);
}img { margin: 0 10px 10px 0; height: 90px; }Прочитайте розділ "Ваш перший компонент", щоб дізнатися, як оголошувати та використовувати компоненти React.
Ви можете оголосити багато компонентів в одному файлі, але великі файли можуть бути заскладними для навігації. Щоб вирішити цю проблему, ви можете експортувати компонент у його власний файл, а потім імпортувати цей компонент з іншого файлу:
import Gallery from './Gallery.js';
export default function App() {
return (
<Gallery />
);
}import Profile from './Profile.js';
export default function Gallery() {
return (
<section>
<h1>Видатні вчені</h1>
<Profile />
<Profile />
<Profile />
</section>
);
}export default function Profile() {
return (
<img
src="https://i.imgur.com/QIrZWGIs.jpg"
alt="Алан Л. Гарт (Alan L. Hart)"
/>
);
}img { margin: 0 10px 10px 0; }Прочитайте розділ "Імпорт та експорт компонентів", щоб дізнатися, як розділити компоненти на декілька файлів.
Кожен компонент React — це функція JavaScript, яка може містити певну розмітку, яку React рендерить у браузері. Компоненти React використовують розширення синтаксису під назвою JSX для представлення цієї розмітки. JSX дуже схожий на HTML, але з трохи більшою кількістю обмежень і з можливістю відображати інформацію, що динамічно змінюється.
Якщо ми вставимо наявну розмітку HTML у компонент React, це не завжди працюватиме:
export default function TodoList() {
return (
// This doesn't quite work!
<h1>Список завдань Геді Ламар</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
<li>Винахід нових світлофорів
<li>Провести репетицію сцени з фільму
<li>Вдосконалення технології спектра
</ul>
);
}img { height: 90px; }Якщо у вас вже є схожий HTML, ви можете виправити його за допомогою конвертера:
export default function TodoList() {
return (
<>
<h1>Список завдань Геді Ламар</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Геді Ламар (Hedy Lamarr)"
className="photo"
/>
<ul>
<li>Винахід нових світлофорів</li>
<li>Провести репетицію сцени з фільму</li>
<li>Вдосконалення технології спектра</li>
</ul>
</>
);
}img { height: 90px; }Прочитайте розділ "Написання розмітки з JSX", щоб дізнатися, як писати правильний JSX.
JSX дозволяє писати HTML-подібну розмітку всередині файлу JavaScript, зберігаючи логіку рендерингу та вміст в одному місці. Іноді вам потрібно додати трохи логіки JavaScript або посилатися на динамічну властивість у цій розмітці. Тоді ви можете використовувати фігурні дужки у своєму JSX, щоб "відкрити вікно" у JavaScript:
const person = {
name: 'Грегоріо І. Зара (Gregorio Y. Zara)',
theme: {
backgroundColor: 'black',
color: 'pink'
}
};
export default function TodoList() {
return (
<div style={person.theme}>
<h1>Список завдань {person.name}</h1>
<img
className="avatar"
src="https://i.imgur.com/7vQD0fPs.jpg"
alt="Gregorio Y. Zara"
/>
<ul>
<li>Покращити відеотелефон</li>
<li>Підготувати лекції з авіаційних технологій</li>
<li>Працювати над двигуном на спиртовому паливі</li>
</ul>
</div>
);
}body { padding: 0; margin: 0 }
body > div > div { padding: 20px; }
.avatar { border-radius: 50%; height: 90px; }Прочитайте розділ "JavaScript у JSX із фігурними дужками", щоб дізнатися, як отримувати доступ до JavaScript-елементів зсередини JSX.
Компоненти React використовують пропси для спілкування один з одним. Кожен батьківський компонент може передавати деяку інформацію своїм дочірнім компонентам, задаючи їхні пропси. Пропси можуть нагадувати вам атрибути HTML, але ви можете передати через них будь-яке значення JavaScript, включно з об'єктами, масивами, функціями та навіть JSX!
import { getImageUrl } from './utils.js'
export default function Profile() {
return (
<Card>
<Avatar
size={100}
person={{
name: 'Кацуко Сарухаші (Katsuko Saruhashi)',
imageId: 'YfeOqp2'
}}
/>
</Card>
);
}
function Avatar({ person, size }) {
return (
<img
className="avatar"
src={getImageUrl(person)}
alt={person.name}
width={size}
height={size}
/>
);
}
function Card({ children }) {
return (
<div className="card">
{children}
</div>
);
}export function getImageUrl(person, size = 's') {
return (
'https://i.imgur.com/' +
person.imageId +
size +
'.jpg'
);
}.card {
width: fit-content;
margin: 5px;
padding: 5px;
font-size: 20px;
text-align: center;
border: 1px solid #aaa;
border-radius: 20px;
background: #fff;
}
.avatar {
margin: 20px;
border-radius: 50%;
}Прочитайте розділ "Передача пропсів до компонента", щоб дізнатися, як передавати та читати пропси.
Ваші компоненти часто повинні відображати різні елементи залежно від різних умов. У React ви можете умовно рендерити JSX за допомогою синтаксису JavaScript, використовуючи вираз if та оператори && і ? :.
У цьому прикладі оператор JavaScript && використовується для умовного рендерингу прапорця:
function Item({ name, isPacked }) {
return (
<li className="item">
{name} {isPacked && '✅'}
</li>
);
}
export default function PackingList() {
return (
<section>
<h1>Список речей для пакування Саллі Райд (Sally Ride)</h1>
<ul>
<Item
isPacked={true}
name="Космічний костюм"
/>
<Item
isPacked={true}
name="Шолом із золотим листям"
/>
<Item
isPacked={false}
name="Фото Тем О'Шонессі (Tam O'Shaughnessy)"
/>
</ul>
</section>
);
}Прочитайте розділ "Умовний рендеринг", щоб дізнатися про різні способи рендерингу вмісту залежно від умов.
Часто потрібно відобразити кілька подібних компонентів із колекції даних. Ви можете використовувати filter() і map() із JavaScript у React, щоб фільтрувати та перетворювати свій масив даних у масив компонентів.
Для кожного елемента масиву вам потрібно буде вказати key. Зазвичай ви хочете використовувати ідентифікатор із бази даних як key. Ключі дозволяють React відстежувати місце кожного елемента у списку, навіть якщо список змінюється.
import { people } from './data.js';
import { getImageUrl } from './utils.js';
export default function List() {
const listItems = people.map(person =>
<li key={person.id}>
<img
src={getImageUrl(person)}
alt={person.name}
/>
<p>
<b>{person.name}:</b>
{' ' + person.profession + ', '}
чиєю працею є {person.accomplishment}
</p>
</li>
);
return (
<article>
<h1>Вчені</h1>
<ul>{listItems}</ul>
</article>
);
}export const people = [{
id: 0,
name: 'Кетрін Джонсон (Creola Katherine Johnson)',
profession: 'математик',
accomplishment: 'розрахунки для космічних польотів',
imageId: 'MK3eW3A'
}, {
id: 1,
name: 'Маріо Моліна (Mario José Molina-Pasquel Henríquez)',
profession: 'хімік',
accomplishment: 'відкриття озонової діри в Арктиці',
imageId: 'mynHUSa'
}, {
id: 2,
name: 'Абдус Салам (Moшинкаmad Abdus Salam)',
profession: 'фізик',
accomplishment: 'теорія електромагнетизму',
imageId: 'bE7W1ji'
}, {
id: 3,
name: 'Персі Джуліан (Percy Lavon Julian)',
profession: 'хімік',
accomplishment: 'новаторські кортизоновмісні препарати, стероїди та протизаплідні таблетки',
imageId: 'IOjWm71'
}, {
id: 4,
name: 'Субрахманьян Чандрасекар (Subrahmanyan Chandrasekhar)',
profession: 'астрофізик',
accomplishment: 'розрахунок мас зір категорії "білий карлик"',
imageId: 'lrWQx8l'
}];export function getImageUrl(person) {
return (
'https://i.imgur.com/' +
person.imageId +
's.jpg'
);
}ul { list-style-type: none; padding: 0px 10px; }
li {
margin-bottom: 10px;
display: grid;
grid-template-columns: 1fr 1fr;
align-items: center;
}
img { width: 100px; height: 100px; border-radius: 50%; }
h1 { font-size: 22px; }
h2 { font-size: 20px; }Прочитайте розділ "Рендеринг списків", щоб дізнатися, як рендерити список компонентів і вибирати ключ.
Деякі функції JavaScript є чистими. Чиста функція (pure function):
- Займається лише своєю справою. Вона не змінює жодних об'єктів чи змінних, які існували до її виклику.
- Однакові вхідні дані — той самий результат. З урахуванням однакових вхідних даних чиста функція має завжди повертати той самий результат.
Пишучи компоненти виключно як чисті функції, ви можете уникнути цілого класу незрозумілих помилок і непередбачуваної поведінки відповідно до того, як ваша кодова база зростатиме. Ось приклад "нечистого" компонента:
let guest = 0;
function Cup() {
// Погано: зміна значення змінної, що вже існувала!
guest = guest + 1;
return <h2>Чашка для гостя #{guest}</h2>;
}
export default function TeaSet() {
return (
<>
<Cup />
<Cup />
<Cup />
</>
);
}Ви можете зробити цей компонент чистим, передавши проп замість модифікації змінної, що вже існувала:
function Cup({ guest }) {
return <h2>Чашка для гостя #{guest}</h2>;
}
export default function TeaSet() {
return (
<>
<Cup guest={1} />
<Cup guest={2} />
<Cup guest={3} />
</>
);
}Прочитайте розділ "Утримання компонентів "чистими"", щоб дізнатися, як писати компоненти у вигляді чистих, передбачуваних функцій.
React використовує дерева для моделювання зв'язків між компонентами та модулями.
Дерево рендерингу React — це представлення батьківського та дочірнього зв'язку між компонентами.
Приклад дерева рендерингу React.
Компоненти, розташовані біля вершини дерева, поблизу кореневого компонента, вважаються верхніми або найвищого рівня (top-level). Компоненти без дочірніх компонентів є листовими компонентами. Ця категоризація компонентів корисна для розуміння потоку даних і продуктивності рендерингу.
Моделювання зв'язків між модулями JavaScript — ще один корисний спосіб зрозуміти вашу програму. Ми називаємо це деревом залежностей модулів.
Приклад дерева залежностей модулів.
Дерево залежностей часто використовується бандлерами, щоб запакувати весь актуальний код JavaScript для завантаження та рендерингу клієнтом. Великий розмір бандла погіршує досвід користування React-застосунками. Розуміння дерева залежностей модулів корисно для усунення таких проблем.
Прочитайте розділ "Ваш UI як дерево", щоб дізнатися, як створюється дерево рендерингу і залежностей модулів у React-застосунках та наскільки вони є корисними абстрактними моделями для покращення досвіду користування і продуктивності.
Перейдіть до розділу "Ваш перший компонент", щоб почати читати цю секцію посторінково!
Або, якщо ви вже знайомі з цими темами, чому б не переглянути "Додавання інтерактивності"?