map().key при роботі зі списками.На минулій лекції ми дізналися, що React будує інтерфейси у вигляді “лего-блоків” — незалежних компонентів. Але як саме створювати ці компоненти?
Історично існували два підходи: створення через Класи (Class Components, старий підхід) та через Функції (Functional Components, сучасний підхід). Сьогодні вся індустрія перейшла виключно на функціональні компоненти, тому що вони простіші для розуміння і містять менше шаблонного (boilerplate) коду.
Окрім компонентів, головною родзинкою React є JSX — синтаксис, що дозволяє писати HTML-теги безпосередньо всередині JavaScript-коду. Спочатку це виглядає неприродно для розробників, які звикли жорстко відділяти логіку (JS) від розмітки (HTML). Але цей підхід робить створення динамічних інтерфейсів набагато зручнішим.
Мета цієї лекції — навчитися створювати функціональні компоненти, вільно писати JSX-розмітку, передавати дані між компонентами за допомогою Props і динамічно виводити великі масиви даних (наприклад, каталоги товарів).
Сучасний React-компонент — це звичайнісінька JavaScript-функція.
Ця функція отримує певні дані (Props) на вхід і завжди зобов’язана повернути (return) шматок UI-розмітки на вихід.
Два головних правила для компонентів:
Button, а не button). Якщо ви напишите з маленької, React подумає, що це звичайний вбудований HTML-тег.Приклад компонента Header.jsx:
// Використовуємо звичайну або стрілочну функцію
function Header() {
return (
<header>
<h1>Вітаємо у React!</h1>
</header>
);
}
export default Header; // Експортуємо, щоб використати в інших місцях
Застосування створеного компонента в головному файлі (наприклад, App.jsx):
import Header from "./Header";
function App() {
return (
<div>
<Header /> {/* Викликаємо компонент як HTML-тег, що самозакривається */}
<main>Основний контент сторінки</main>
</div>
);
}
JSX — це синтаксичний цукор (надбудова над JS). Браузер насправді не розуміє JSX. Під капотом інструменти збірки (наприклад, Vite + Babel) перетворюють кожен тег <h1>Привіт</h1> на складний і нечитабельний виклик функції React.createElement('h1', null, 'Привіт'). JSX створений тільки для того, щоб розробникам було зручно візуально уявляти DOM-дерево.
Найважливіша фішка JSX — вставка JavaScript всередину HTML.
Щоб вставити будь-який динамічний вираз JS (змінну, результат виклику функції, математичну операцію) у розмітку, достатньо взяти його у фігурні дужки {}.
function UserProfile() {
const name = "Олег";
const age = 25;
const currentYear = new Date().getFullYear(); // 2026
return (
<div className="card">
<h2>Ім'я користувача: {name.toUpperCase()}</h2>
<p>Вік: {age}</p>
<p>Рік народження: {currentYear - age}</p>
</div>
);
}
Важливо: У фігурні дужки можна вставляти ТІЛЬКИ вирази (expressions), які повертають значення. (Не можна вставити туди цикл
forабо конструкціюif...else).
return <h1>...</h1> <p>...</p>;<div>...</div>. Якщо ви не хочете плодити “сміттєві” діви створюючи div-soup, використовуйте React Фрагменти: порожні теги <> ... </>. Вони зникають після рендерингу в браузері.img, br, input), у JSX зобов’язані закриватися: <img src="logo.png" /> або <input type="text" />.class змінюється на className: Оскільки “class” — це зарезервоване (ключове) слово в JavaScript (для створення ООП-класів), React використовує атрибут className для прив’язки CSS-класів. У фінальному HTML він перетвориться на звичайний class.onclick стає onClick, tabindex стає tabIndex).Компоненти були б не дуже корисними, якби вони малювали завжди одне й те саме захардкоджене значення. Нам потрібно мати можливість “передавати налаштування” всередину компонента. Для цього використовуються Props (скорочення від Properties).
Props — це об’єкт з даними, які ми передаємо зверху-вниз: від Компонента-Батька до Компонента-Дитини. Синтаксично це виглядає як передача звичайних HTML-атрибутів:
Батьківський компонент App.jsx:
import WelcomeBox from "./WelcomeBox";
function App() {
return (
<div>
{/* Передаємо пропси name, age та role */}
<WelcomeBox name="Олена" age={28} role="Адмін" />
<WelcomeBox name="Ігор" age={19} role="Користувач" />
</div>
);
}
Зверніть увагу: рядки передаються в лапках " ", а числа (або об’єкти, чи масиви) ОБОВ’ЯЗКОВО беруться у фігурні дужки {28}.
Як дитячий компонент приймає ці дані? Він отримує їх як єдиний аргумент-об’єкт props.
// Варіант 1: Довгий (без деструктуризації)
function WelcomeBox(props) {
return (
<article>
<p>Привіт, {props.name}!</p>
<small>Вік: {props.age}</small>
</article>
);
}
Але в сучасному React всі використовують деструктуризацію безпосередньо в параметрах функції і відразу отримують потрібні змінні. Також тут зручно призначати значення за замовчуванням (=), якщо батько раптом забув передати prop.
// Варіант 2: Сучасний (з деструктуризацією)
function WelcomeBox({ name, age, role = "Гість" }) {
return (
<article>
<p>
Привіт, {name} (статус: {role})!
</p>
<small>Вік: {age}</small>
</article>
);
}
Золоте правило Props: Пропси є “Тільки для читання” (Read-Only). Компонент-дитина ніколи не має права змінювати пропси, які йому передали! Це грубе порушення архітектуриReact (і згенерує помилку).
map()Майже у кожному додатку (від стрічки Instagram до списку товарів у Rozetka) доводиться перетворювати масив сирих даних із бекенду на великий список HTML/JSX-елементів.
В React це робиться виключно за допомогою стандартного методу масивів map().
Оскільки map повертає новий масив і є виразом, ми пишемо його прямо у JSX, всередині фігурних дужок {}:
const usersData = [
{ id: 1, name: "Анна" },
{ id: 2, name: "Богдан" },
{ id: 3, name: "Віктор" },
];
function UserList() {
return (
<ul>
{usersData.map((user) => (
// Зверніть увагу: використовуємо дужки () для повернення JSX, a не {}
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Замість простого <li> ми могли б повертати складний компонент <UserCard name={user.name} /> і відмалювати тисячі карток трьома рядками коду.
keyЯкщо ви виконаєте код вище без атрибута key, React виведе в консоль яскраве червоне попередження:
Warning: Each child in a list should have a unique "key" prop.
Навіщо потрібен key?
Коли список великий і динамічний (товари можна видаляти, сортувати, додавати), React-у важко слідкувати за тим, який саме елемент змінився, якщо всі вони є просто тегами <li>.
Атрибут key — це унікальний бейдж (паспорт) для кожного елемента списку.
Завдяки ключам алгоритм Реконсиляції Віртуального DOM (Diffing) працює блискавично. Якщо ми видалимо другий елемент, React (дивлячись на ключі) зрозуміє саме це видалення і не буде перемальовувати решту 999 елементів списку.
Правила key:
Math.random()).ID із бази даних (id: 12345).map((user, index)) у якості key — вважається крайнім антипатерном, оскільки при сортуванні або видаленні з масиву індекси змістяться і React заплутається і зрендерить хибні дані. Використовувати індекси можна тільки якщо список суто статичний і ніколи не мінятиметься.А що, якщо ми хочемо показувати компонент <AdminPanel />, якщо isAdmin === true, і загальний <ErrorText />, якщо false? У React не можна просто вставити класичний if всередину JSX-розмітки return (...).
Є два улюблені способи умовного показу в React (вбудовуються у {}):
1. Тернарний оператор (Умова ? Так : Ні) Використовується, коли є два альтернативних варіанти.
function Dashboard({ isAdmin }) {
return (
<div>
{isAdmin ? <AdminPanel /> : <p>Доступ заборонено (ви не адмін).</p>}
</div>
);
}
2. Логічне АБО (Умова && Так)
Використовується, коли у разі негативної умови взагалі нічого не потрібно малювати. Якщо перша частина true, друга відмальовується. Якщо false, друга частина ігнорується.
function ShoppingCart({ cartItems }) {
// Якщо масив не пустий (>0) - показуємо кнопку "Оплатити"
return (
<div>
<ul>{/*...тут товари...*/}</ul>
{cartItems.length > 0 && <button>Оплатити замовлення</button>}
</div>
);
}
{}.<></>), атрибут className та самозакриття всіх тегів — базові вимоги JSX-синтаксису.Props — це механізм потоку даних згори-донизу. Через пропси батьки “налаштовують” дітей. Пропси в дитині є Read-Only (змінювати їх не можна)..map().map, завжди необхідно передавати унікальний стабільний key до головного вузла обгортки (зазвичай ID з бази даних). Це критично для продуктивності React.? : або логічного “І” && безпосередньо у фігурних дужках.key важливий.<> </>)?Props. У якому напрямку між компонентами можлива їхня передача? Чи має право син-компонент поміняти те, що йому передали?title та color (де color за замовчуванням буде “black”).className замість класичного HTML-атрибута class?Math.random()) або індексів масиву у якості key в списках — це погана практика і може викликати страшні баги? Яке джерело для значення атрибута key є еталонним?