JSTAcademy
0 XP
Dashboard
Crash Courses
useEffect & Side Effects
11 min
Basic+150 XP
Crash Courses · Basic

useEffect & Side Effects

Sync React components with external systems, data, and browser APIs using useEffect.
11 min read+150 XP on completionCert: React Crash Course
Tap any word in the text below to start reading from there.

useEffect & Side Effects

useEffect synchronizes components with external systems data fetching, subscriptions, timers, and DOM APIs.

Basic useEffect

import { useState, useEffect } from 'react'

function DocumentTitle({ title }: { title: string }) {
  useEffect(() => {
    document.title = title
  }, [title])  // runs when title changes

  return null
}

Data Fetching Pattern

function CourseDetail({ courseId }: { courseId: string }) {
  const [course, setCourse] = useState<Course | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    let cancelled = false

    async function load() {
      try {
        setLoading(true)
        const res = await fetch(`/api/courses/${courseId}`)
        const data = await res.json()
        if (!cancelled) {
          setCourse(data)
        }
      } catch (err) {
        if (!cancelled) setError('Failed to load')
      } finally {
        if (!cancelled) setLoading(false)
      }
    }

    load()
    return () => { cancelled = true }  // cleanup — prevent stale state
  }, [courseId])

  if (loading) return <Spinner />
  if (error) return <Error message={error} />
  if (!course) return null
  return <CourseView course={course} />
}

Dependency Array Rules

// [] — run once on mount, cleanup on unmount
useEffect(() => {
  const id = setInterval(tick, 1000)
  return () => clearInterval(id)
}, [])

// [dep] — run when dep changes
useEffect(() => {
  fetchUser(userId)
}, [userId])

// No array — run on every render (rarely needed)
useEffect(() => {
  console.log('rendered')
})

Subscription Cleanup

useEffect(() => {
  const subscription = store.subscribe(handler)
  return () => subscription.unsubscribe()
}, [])

useEffect(() => {
  window.addEventListener('resize', handleResize)
  return () => window.removeEventListener('resize', handleResize)
}, [])
0%