Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Запити в тілі компонента». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)Запит у тілі компонента виконується при кожному рендері (яких може бути десятки через зміну state, props, контексту чи батьківський рендер), а React очікує, що компонент - це чиста функція, яка повертає JSX без побічних ефектів. **Ключове:** асинхронний запит - це побічний ефект, тому його потрібно виносити в `useEffect`, який React виконує після рендера, а не під час нього.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Чому не можна робити запити в тілі компонента ### 1. Компонент може рендеритися багато разів React **викликає компонент як звичайну функцію** при кожному рендері: ```javascript function User() { console.log('render'); // ... return <div>...</div>; } ``` Якщо всередині тіла компонента ви напишете запит: ```javascript function User() { fetch('/api/user') // невірно return <div>...</div>; } ``` цей `fetch()` буде виконуватися **при кожному рендері**, а рендерів може бути **десятки**: - через зміну `state`; - через зміну `props`; - через контекст; - через батьківський рендер; - у React 18 - навіть **двічі** в dev-режимі (Strict Mode). У результаті ви отримаєте **безліч однакових запитів**, навантаження на мережу і "мерехтливий" інтерфейс. --- ### 2. React вимагає чистих компонентів Компонент у React має бути **чистою функцією**: > та сама функція з однаковими вхідними даними (props/state) > завжди повинна повертати однаковий JSX без побічних ефектів. Асинхронний запит (`fetch`, `axios`, `localStorage`, `WebSocket`) - це **побічний ефект**: він змінює зовнішній світ, робить HTTP-виклик і не є детермінованим. React очікує, що: ```javascript render(props) → JSX ``` а не: ```javascript render(props) → побічний ефект + JSX ``` Тому такі операції потрібно виносити в **ефекти (**`useEffect`**)**, які React виконує **після рендера**, коли безпечно виконувати асинхронні дії. --- ### 3. Асинхронні операції ламають фазу рендера Якщо зробити `await` прямо в тілі: ```javascript async function User() { const res = await fetch('/api/user'); // невірно const user = await res.json(); return <p>{user.name}</p>; } ``` React **не буде чекати цей** `await` - він просто побачить, що компонент повернув **Promise замість JSX**, і видасть помилку. Виняток - **React Server Components (RSC)** у Next.js 13+: там серверні компоненти дійсно можуть бути `async`, тому що рендер виконується на сервері, де React вміє "дочекатися" `await`. Але **в клієнтських компонентах** (звичайні React-застосунки) це **неможливо**. --- ### 4. Ризик нескінченного циклу Якщо ви записуєте результат запиту в стан прямо в тілі: ```javascript function User() { const [data, setData] = useState(); fetch('/api/user') .then(res => res.json()) .then(setData); return <p>{data?.name}</p>; } ``` то при кожному `setData()` -> викликається новий рендер -> знову `fetch()` -> знову `setData()`... **Нескінченний цикл запитів** і завислий інтерфейс. --- ## Як правильно Використовувати `useEffect()`: ```javascript function User() { const [data, setData] = useState(null); useEffect(() => { fetch('/api/user') .then(res => res.json()) .then(setData) .catch(console.error); }, []); // порожній масив залежностей = виконається один раз при монтуванні if (!data) return <p>Loading...</p>; return <p>{data.name}</p>; } ``` --- ## Підсумок | Робити запит у тілі компонента | Робити запит у `useEffect` | |---|---| | Виконується при кожному рендері | Виконується після монтування | | Створює побічний ефект під час рендера | Побічний ефект виконується контрольовано | | Може призвести до нескінченних запитів | Виконується один раз або за потрібними залежностями | | Порушує принцип "чистої функції" | Дотримується React-парадигми "рендер -> ефект" |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.