// src/App.jsx import { useEffect, useState } from "react"; function useFetch(url) { const [data, setData] = useState(null); const [status, setStatus] = useState("idle"); useEffect(() => { let ignore = false; setStatus("loading"); async function loadData() { try { const response = await fetch(url); if (!response.ok) throw new Error("Request failed"); const result = await response.json(); if (!ignore) { setData(result); setStatus("success"); } } catch (err) { if (!ignore) setStatus("error"); } } loadData(); return () => { ignore = true; }; }, [url]); return { data, status }; } function JokeWidget() { const { data, status } = useFetch("https://official-joke-api.appspot.com/random_joke"); if (status === "loading") return

Loading joke...

; if (status === "error") return

Failed to load joke.

; return

{data?.setup}

; } function UserWidget() { const { data, status } = useFetch("https://jsonplaceholder.typicode.com/users/1"); if (status === "loading") return

Loading user...

; if (status === "error") return

Failed to load user.

; return

{data?.name}

; } function App() { return (
); } export default App; /* Notes: - JokeWidget and UserWidget each call useFetch with their own URL — every piece of state useFetch manages internally is completely independent between the two calls. - Neither component contains any fetch, try/catch, or status logic itself anymore — that's the whole benefit of the extraction. */