Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Запит при першому рендері». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Запит при першому рендері** виконується в `useEffect` з **порожнім масивом залежностей** `[]` (тільки при першому монтуванні), не забуваючи про **скасування** і **обробку помилок**. **Ключове:** `AbortController` обов'язковий, щоб не ловити `setState` на демонтованому компоненті і не витрачати мережу даремно.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)ЗображенняКоротко: роби запит у `useEffect` з **порожнім масивом залежностей** `[]` (тільки при першому монтуванні), не забувай про **скасування** і **обробку помилок**. Нижче - надійний шаблон. ```javascript import { useEffect, useState, useRef } from "react"; export function UserOnce() { const [data, setData] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(true); // Страховка від подвійного виклику ефекту в Dev-режимі (StrictMode) у React 18 const didRunRef = useRef(false); useEffect(() => { if (didRunRef.current) return; // не даємо запуститися вдруге в Dev didRunRef.current = true; const controller = new AbortController(); (async () => { try { setLoading(true); const res = await fetch("/api/user", { signal: controller.signal }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const json = await res.json(); setData(json); // оновлюємо стан тільки якщо не скасували } catch (e) { if (e.name !== "AbortError") setError(e); } finally { setLoading(false); } })(); // cleanup: скасовуємо запит при демонтуванні return () => controller.abort(); }, []); // ← тільки перший рендер (монтування) if (loading) return <p>Loading...</p>; if (error) return <p>Error: {String(error.message || error)}</p>; return <pre>{JSON.stringify(data, null, 2)}</pre>; } ``` ### Важливі моменти - **Чому** `[]`**:** ефект виконається один раз - при монтуванні компонента. - **StrictMode в Dev (React 18):** ефекти можуть викликатися двічі. Прапорець `useRef` вище запобігає повторному запиту при розробці. У проді ефект виконається один раз. - **Скасування запиту:** `AbortController` - must-have, щоб не ловити `setState` на демонтованому компоненті і не витрачати мережу. - **Звідки брати параметри:** якщо запит залежить від `props/state` (наприклад, `userId`), включай їх у залежності: ```javascript useEffect(() => { // ...запит з userId... }, [userId]); ``` і показуй `loading` при зміні `userId`. - **Альтернатива:** бібліотеки на кшталт **TanStack Query (React Query)** і **SWR** беруть на себе кеш, скасування, повтор, stale-while-revalidate тощо, спрощуючи код.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.