Модуль 25

Архітектура React-застосунку

Ось твій урок у стилі David Malan. Уяви, що ми в лекційній залі, я ходжу сценою, активно жестикулюю, а на екрані за мною — код і меми. Поїхали!


🏛 Архітектура React-застосунку: Від хаосу до порядку

1. 🔥 Вступ: Хаос у шухляді

Уявіть, що ви збираєтеся в подорож. Ви відкриваєте свою «шухляду з усім на світі» — ту саму, де лежать старі зарядки, батарейки, квитанції за 2019 рік, ключі невідомо від чого і, можливо, навушники.

Вам потрібно знайти зарядку для телефону. Ви витрачаєте 10 хвилин, розплутуючи вузли. Ви нервуєте. Ви спізнюєтесь.

А тепер уявіть, що ваш React-проєкт — це ця шухляда. Коли ви тільки починали (create-react-app), у вас був один файл App.js. Це було просто. Але минув тиждень, ви додали логін, кошик, список товарів, аналітику... І тепер ваш App.js має 2000 рядків коду.

Питання до вас: Що станеться, якщо я попрошу вас змінити колір кнопки «Купити» на всіх сторінках? Або якщо я скажу, що логіка авторизації зламалася?

Ви будете «порпатися в шухляді». Це — погана архітектура.

Сьогодні ми не просто вчимося писати код. Ми вчимося бути архітекторами. Ми перетворимо вашу «шухляду з мотлохом» на професійну кухню мішленівського ресторану, де шеф (це ви) точно знає, де лежить ніж, а де — спеції.


2. 🧠 Теоретична база: Структура — це не просто папки

Архітектура в React — це про те, хто за що відповідає і де це лежить.

Як це працює «під капотом»?

React — це дерево компонентів. Але якщо ви кинете всі гілки в одну купу, дерево не виросте. Браузеру все одно, як ви розклали файли, він зчитає все. Архітектура потрібна вам і вашій команді, щоб не збожеволіти.

🔑 Ключові поняття (запам'ятати):

  1. Розділення обов’язків (Separation of Concerns):

    • Це як у ресторані: офіціант (UI) не готує їжу, а кухар (Logic) не носить тарілки.
    • У React: UI-компоненти (кнопки, картки) мають бути тупими. Вони просто показують те, що їм дали. Логіка (запити до сервера, обробка даних) має жити окремо (наприклад, у хуках).
  2. Структура тек (Folder Structure): Це ваша мапа місцевості. Стандартна «хороша» структура виглядає так:

    • /components — цеглинки лего (кнопки, інпути, хедер).
    • /pages — готові сторінки, зібрані з цеглинок.
    • /hooks — ваша бізнес-логіка (як працює, а не як виглядає).
    • /utils або /helpers — маленькі помічники (наприклад, форматування дати).
  3. Colocation (Співрозміщення): Тримайте речі там, де ви їх використовуєте. Якщо стиль потрібен лише одній кнопці, не кладіть його в глобальний CSS. Покладіть його поруч із кнопкою.


3. 🧪 Приклади: Еволюція коду

Давайте подивимось, як це виглядає на практиці.

Етап 1: "Спагетті-код" (Як роблять новачки)

Подивіться на цей код. Що тут не так?

// App.js
function App() {
  const [user, setUser] = useState(null);

  // Логіка перемішана з версткою
  useEffect(() => {
    fetch('/api/user').then(data => setUser(data));
  }, []);

  if (!user) return <div>Loading...</div>;

  return (
    <div style={{ padding: 20 }}>
      <header style={{ backgroundColor: 'blue' }}>
        <h1>Привіт, {user.name}</h1>
      </header>
      {/* 200 рядків коду картки товару прямо тут */}
      <div className="product">
         <h2>Айфон 15</h2>
         <button onClick={() => alert('Куплено')}>Купити</button>
      </div>
    </div>
  );
}

Що не так? Все в одному файлі. Стилі, запити до сервера, верстка. Якщо я захочу використати цю кнопку в іншому місці — мені доведеться копіювати код (Ctrl+C / Ctrl+V — це ворог розробника).


Етап 2: "Розумна структура" (Як робите ви після цього уроку)

Ми розбиваємо це на частини.

1. /components/Button.jsx (Тупий компонент) Він нічого не знає про товари чи користувачів. Він просто кнопка.

export const Button = ({ onClick, children, variant = 'primary' }) => (
  <button className={`btn-${variant}`} onClick={onClick}>
    {children}
  </button>
);

2. /hooks/useUser.js (Чиста логіка)

export const useUser = () => {
  const [user, setUser] = useState(null);
  // Логіка завантаження...
  return { user };
};

3. /pages/Dashboard.jsx (Місце зустрічі)

import { Button } from '../components/Button';
import { useUser } from '../hooks/useUser';

export const Dashboard = () => {
  const { user } = useUser();

  if (!user) return <Loading />;

  return (
    <div>
      <Header name={user.name} />
      <ProductCard title="Айфон 15">
        <Button onClick={() => console.log('Buy!')}>Купити</Button>
      </ProductCard>
    </div>
  );
};

Чому це круто? Дивіться на Dashboard. Він чистий. Він читається як книга англійською мовою. Ви одразу бачите структуру, а деталі (який колір у кнопки, як саме ми беремо юзера) сховані.


4. 🛠 Практична частина

Час закачати рукави. Ось ваші завдання:

  1. 🔹 Рефакторинг: У вас є компонент UserProfile, де всередині є fetch запит і велика верстка форми редагування.
    • Завдання: Винесіть форму в окремий компонент EditUserForm, а логіку запиту — в кастомний хук useUserProfile.
  2. 🔹 Універсалізація: Створіть компонент Card. Він має приймати title і children.
    • Завдання: Використайте цей Card для відображення профілю юзера і для відображення товару. Переконайтесь, що він виглядає гарно в обох випадках.
  3. 🔹 Структура папок: У вас є файл utils.js з функціями formatDate, calculateTax, validateEmail.
    • Завдання: Це стає смітником. Як краще це організувати? (Підказка: створіть папку /utils і розбийте на файли за змістом).
  4. 🔹 "А що, якщо...": Уявіть, що дизайнер змінив стиль усіх кнопок на сайті. Вони тепер круглі.
    • Питання: Скільки файлів вам доведеться змінити у вашій новій архітектурі? (Правильна відповідь: один, Button.jsx).
  5. 🔹 Міні-кейс: Вам потрібно додати "Темну тему". Де ви будете зберігати стан теми (світла/темна), щоб він був доступний усьому застосунку? (Подумайте про структуру, не пишіть код).

5. 💡 Мислення як у розробника

Як відрізнити новачка від сеньйора, дивлячись на структуру проекту?

❌ Помилки новачків:

  • Глибока вкладеність: src/components/users/profile/header/avatar/image.js. Ви втомитеся це відкривати. Тримайте структуру пласкою, поки це можливо.
  • Все "Reusable": Намагатися зробити кнопку, яка вміє абсолютно все (і іконку, і лоадер, і 50 стилів). Це призводить до монстрів. Краще мати дві різні прості кнопки, ніж одну монструозну.
  • index.js усюди: Коли у вас 50 файлів index.js у різних папках, пошук у редакторі (Ctrl+P) перетворюється на пекло. Краще називати файли Button.jsx, а не Button/index.js.

✅ Як думає профі:

  • Принцип YAGNI (You Aren't Gonna Need It): Не створюйте складну архітектуру для лендінгу з трьох блоків. Архітектура має відповідати складності задачі.
  • Імена мають значення: Називайте компоненти так, щоб через рік ви зрозуміли, що це. ContentWrapper — погано. ProductGrid — добре.
  • Правило бойскаута: Залишай код чистішим, ніж ти його знайшов. Побачив дублювання? Винеси в компонент.

6. 🧩 Підсумок

Отже, що ми сьогодні зробили? 1. Зрозуміли, що архітектура — це гігієна коду. Без неї проєкт помирає під власною вагою. 2. Навчилися розділяти UI (презентацію) та Логіку. 3. Побачили силу папки /components та /hooks.

Тепер ви можете створювати застосунки, які легко розширювати. Ви не просто "кодери", ви будуєте фундамент.

Наступного разу: Ви помітили, що передавати дані через 5 компонентів вниз (prop drilling) трохи втомлює?

"Мамо, передай татові, щоб передав брату, щоб той увімкнув світло".

На наступному уроці ми вирішимо це за допомогою Context API та Global State Managers. Це буде магія телепортації даних!

А поки — це був CS50 React Edition. Щасти вам! 🖥️👋