Skip to content
    SeaCode
    Learning tracksCode ArenaWorkshops & EventsInstructors
    Log inSign up
    ⚛React

    Components and JSX

    • Why React?
    • JSX rules
    • Props
    • Rendering lists and keys
    • Conditional rendering

    State and events

    • Handling events
    • useState: a component's memory
    • Objects and arrays in state
    • Forms and controlled inputs
    • Lifting state up

    Effects and essential hooks

    • useEffect
    • Fetching data
    • useRef
    • Context: data for the whole tree
    • useReducer

    Professional React

    • Writing your own hooks
    • Performance: memo, useMemo and useCallback
    • Suspense and error boundaries
    • What's new in React 19
    • Thinking in React
    • Project: a complete to-do app
    React

    Effects and essential hooks · Lesson 12 of 21

    Fetching data

    Loading, error and data, race conditions, and why libraries help.

    11 minutes2 games

    Every API request has three states: loading, failed or loaded, and the UI must show all three. Here's the basic pattern of fetch inside useEffect (calling a public test API):

    React
    function App() {
      const [users, setUsers] = useState([])
      const [status, setStatus] = useState("loading")
    
      useEffect(() => {
        fetch("https://jsonplaceholder.typicode.com/users?_limit=4")
          .then((res) => {
            if (!res.ok) throw new Error("HTTP " + res.status)
            return res.json()
          })
          .then((data) => { setUsers(data); setStatus("done") })
          .catch((err) => { console.error(err.message); setStatus("error") })
      }, [])
    
      if (status === "loading") return <p>Loading…</p>
      if (status === "error") return <p>Couldn't load users.</p>
      return <ul>{users.map((u) => <li key={u.id}>{u.name} · {u.email}</li>)}</ul>
    }

    Race conditions

    If the user switches quickly, an old response can arrive after the new one and overwrite it, showing the wrong data. The fix: in the cleanup, mark that request as no longer relevant, or cancel it with AbortController. This example uses a fake API with random delays; switch quickly between students:

    React
    const fakeApi = (id) =>
      new Promise((resolve) => setTimeout(() => resolve({ id, xp: id * 100 }), Math.random() * 800))
    
    function Profile({ id }) {
      const [data, setData] = useState(null)
      useEffect(() => {
        let ignore = false                       // this request is still the latest one
        setData(null)
        fakeApi(id).then((d) => { if (!ignore) setData(d) })
        return () => { ignore = true }           // a newer id arrived: ignore this answer
      }, [id])
      return <p>{data ? "Student " + data.id + " has " + data.xp + " xp" : "Loading…"}</p>
    }
    
    function App() {
      const [id, setId] = useState(1)
      return (
        <div>
          {[1, 2, 3, 4].map((n) => <button key={n} onClick={() => setId(n)}>{n}</button>)}
          <Profile id={id} />
        </div>
      )
    }

    request id=1 (slow)

    request id=2 (fast) → cleanup ignores the first

    response 2 arrives and shows

    response 1 arrives late and is ignored

    Important

    In real projects don't hand-write this every time. Libraries like SWR (which SeaCode uses) and TanStack Query handle caching, retries, de-duplication, race conditions and background refresh. In Next.js it's better still to fetch on the server in Server Components (next track).

    Quick question

    Why do we need ignore or AbortController in the cleanup?

    Interview question

    How do you fetch data properly in React, and what's wrong with fetch in useEffect?

    Exercise

    Use fakeCourses() (provided) to load the courses. Show Loading… first, then once they arrive show the count as 3 courses with their titles in a <ul> below.

    The page should show:
    3 courses
    HTML & CSS
    JavaScript
    React
    React
    const fakeCourses = () =>
      new Promise((resolve) => setTimeout(() => resolve(["HTML & CSS", "JavaScript", "React"]), 150))
    
    function App() {
      return <p>Loading…</p>
    }

    Learn more from

    • react.dev: Fetching data with effectsreact.dev
    • SWR: React Hooks for data fetchingswr.vercel.app
    • MDN: Using the Fetch APIdeveloper.mozilla.org
    • MDN: AbortControllerdeveloper.mozilla.org

    Played 0 of 2 games

    Sign in to save your progress and earn XP.

    PrevioususeEffectNextuseRef
    SeaCode

    Learn to code for real, online or at our branch in front of Cairo University, Giza.

    Learn

    • All courses
    • Interactive tutorials
    • Interview practice problems
    • Mock interview
    • Learning tracks
    • Code Arena
    • Workshops & Events
    • Knowledge library
    • Team projects

    Your account

    • Log in
    • Sign up
    • Learning plan
    • Certificates
    • Site map

    Contact us

    • WhatsApp
    • 010 9094 1104
    • In front of Cairo University, Giza

    © 2026 SeaCode. All rights reserved.