Тема: Побудова ієрархії компонентів Практична задача з декомпозиції складного макета на дрібні, перевикористовувані модулі.
Мета: Навчитися аналізувати макети інтерфейсу (UI) та розбивати їх на деревовидну структуру React-компонентів; зрозуміти принципи розподілу відповідальності (Separation of Concerns) між Smart (контейнерними) та Dumb (презентаційними) компонентами; опанувати механізм передачі даних зверху вниз (Prop Drilling).
Необхідні інструменти: Текстовий редактор (VS Code), Node.js, браузер з встановленим розширенням React Developer Tools.
Уявімо, що перед нами стоїть завдання розробити сторінку профілю користувача (“User Dashboard”). Дивлячись на типовий макет, ми маємо розбити його на компоненти:
Презентаційні компоненти відповідають виключно за те, ЯК виглядають речі (UI). Вони отримують дані через props і повертають JSX. Вони не роблять запитів до мережі і рідко мають власний стан.
Створимо найнижчий рівень структури — ActivityItem:
// src/components/ActivityItem.jsx
import React from "react";
const ActivityItem = ({ action, date }) => {
return (
<div style=>
<p style=>{action}</p>
<small style=>{date}</small>
</div>
);
};
export default ActivityItem;
Створимо ще один презентаційний компонент UserInfo:
// src/components/UserInfo.jsx
import React from "react";
const UserInfo = ({ name, email, role }) => {
return (
<div
style=
>
<h2>{name}</h2>
<p>Email: {email}</p>
<p>
Посада: <strong>{role}</strong>
</p>
</div>
);
};
export default UserInfo;
Наступний рівень ієрархії об’єднує дрібніші компоненти (рендер списку).
Створимо ActivityList:
// src/components/ActivityList.jsx
import React from "react";
import ActivityItem from "./ActivityItem";
const ActivityList = ({ activities }) => {
if (!activities || activities.length === 0) {
return <p>Немає останніх активностей.</p>;
}
return (
<div>
<h3>Остання активність</h3>
{activities.map((item) => (
<ActivityItem key={item.id} action={item.action} date={item.date} />
))}
</div>
);
};
export default ActivityList;
Контейнерний компонент (часто це Сторінка) відповідає за те, ЩО роблять речі (Логіка, Стан). Він безпосередньо взаємодіє зі станом (useState) або хуками отримання даних.
Створимо ProfilePage:
// src/pages/ProfilePage.jsx
import React, { useState, useEffect } from "react";
import UserInfo from "../components/UserInfo";
import ActivityList from "../components/ActivityList";
const ProfilePage = () => {
// Контейнер тримає стан
const [userData, setUserData] = useState(null);
const [activities, setActivities] = useState([]);
// Імітація запиту на сервер
useEffect(() => {
// В реальному житті тут був би fetch() або axios
setUserData({
name: "Іван Бойко",
email: "ivan.boyko@example.com",
role: "Frontend Розробник",
});
setActivities([
{ id: 1, action: "Увійшов у систему", date: "Сьогодні, 10:00" },
{ id: 2, action: "Оновив профіль", date: "Вчора, 14:30" },
{ id: 3, action: "Завантажив звіт", date: "12 Вересня" },
]);
}, []);
// Поки дані "завантажуються"
if (!userData) {
return <div>Завантаження профілю...</div>;
}
return (
<div style=>
<aside style=>
<UserInfo
name={userData.name}
email={userData.email}
role={userData.role}
/>
</aside>
<main style=>
<ActivityList activities={activities} />
</main>
</div>
);
};
export default ProfilePage;
Використання React Developer Tools на цьому етапі покаже вам дерево:
ProfilePage -> [UserInfo, ActivityList -> [ActivityItem, ActivityItem, ActivityItem]].
ProductContainer -> ProductDetails, ProductActions -> StarRating, Button).props..map()) зазвичай знаходиться на рівні проміжних композиційних компонентів (наприклад, ActivityList), а не всередині атомарних (наприклад, ActivityItem)?