Suggest an editImprove this articleRefine the answer for “Requests in a component's body”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)A request in a component's body runs on every render (and there can be dozens of those from state, props, context, or a parent re-render), while React expects a component to be a pure function that returns JSX without side effects. **Key point:** an async request is a side effect, so it needs to be moved into `useEffect`, which React runs after the render, not during it.Shown above the full answer for quick recall.Answer (EN)Image## Why you can't make requests in a component's body ### 1. A component can render many times React **calls the component like a regular function** on every render: ```javascript function User() { console.log('render'); // ... return <div>...</div>; } ``` If you write a request inside the component's body: ```javascript function User() { fetch('/api/user') // wrong return <div>...</div>; } ``` this `fetch()` will run **on every render**, and there can be **dozens** of those: - due to a `state` change; - due to a `props` change; - due to context; - due to a parent's render; - in React 18, even **twice** in dev mode (Strict Mode). As a result, you get **a bunch of duplicate requests**, network load, and a "flickering" interface. --- ### 2. React requires pure components A component in React must be a **pure function**: > the same function with the same inputs (props/state) > must always return the same JSX without side effects. An async request (`fetch`, `axios`, `localStorage`, `WebSocket`) is a **side effect**: it changes the outside world, makes an HTTP call, and isn't deterministic. React expects: ```javascript render(props) → JSX ``` not: ```javascript render(props) → side effect + JSX ``` So such operations need to be moved into **effects (**`useEffect`**)**, which React runs **after the render**, when it's safe to perform asynchronous actions. --- ### 3. Async operations break the render phase If you do `await` right in the body: ```javascript async function User() { const res = await fetch('/api/user'); // wrong const user = await res.json(); return <p>{user.name}</p>; } ``` React **won't wait** for that `await`. It will just see that the component returned a **Promise instead of JSX** and throw an error. The exception is **React Server Components (RSC)** in Next.js 13+: there, server components can genuinely be `async`, because the render happens on the server, where React can "wait" for `await`. But **in client components** (regular React apps) this is **not possible**. --- ### 4. The risk of an infinite loop If you write the request's result into state right in the body: ```javascript function User() { const [data, setData] = useState(); fetch('/api/user') .then(res => res.json()) .then(setData); return <p>{data?.name}</p>; } ``` then every `setData()` triggers a new render, which triggers `fetch()` again, which triggers `setData()` again... An **infinite loop of requests** and a frozen UI. --- ## The right way Use `useEffect()`: ```javascript function User() { const [data, setData] = useState(null); useEffect(() => { fetch('/api/user') .then(res => res.json()) .then(setData) .catch(console.error); }, []); // empty dependency array = runs once on mount if (!data) return <p>Loading...</p>; return <p>{data.name}</p>; } ``` --- ## Summary | Making the request in the component's body | Making the request in `useEffect` | |---|---| | Runs on every render | Runs after mounting | | Creates a side effect during the render | The side effect runs in a controlled way | | Can lead to infinite requests | Runs once or on the needed dependencies | | Violates the "pure function" principle | Follows the React "render -> effect" paradigm |For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.