APEX Educational Institute

React Hooks Explained: useState and useEffect with Examples

Understand React's two most important hooks, useState and useEffect, with practical examples (counter, form, data fetching), dependency arrays, cleanup and common mistakes.

Intermediate | 3 min read | Updated

Hooks let React function components hold state and react to changes. Almost every React component you write uses useState, and most data-driven ones use useEffect.

useState: remember a value between renders

jsx
import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      Clicked {count} times
    </button>
  );
}
  • useState(0) sets the initial value.
  • It returns the current value and a setter function.
  • Calling the setter re-renders the component with the new value.

Update based on the previous value

When the new value depends on the old one, pass a function. This is safe even when several updates happen quickly.

jsx
setCount((prev) => prev + 1);

State with objects: always create a new object

jsx
const [form, setForm] = useState({ name: "", email: "" });

function handleChange(e) {
  setForm((prev) => ({ ...prev, [e.target.name]: e.target.value }));
}

return (
  <form>
    <input name="name" value={form.name} onChange={handleChange} />
    <input name="email" value={form.email} onChange={handleChange} />
  </form>
);

Never mutate state directly (form.name = "Ravi"). React compares references, so a mutated object may not trigger a re-render.

useEffect: sync with things outside React

Use useEffect for side effects: fetching data, subscriptions, timers, or updating the document title.

jsx
import { useEffect, useState } from "react";

function CourseList() {
  const [courses, setCourses] = useState([]);
  const [error, setError] = useState(null);

  useEffect(() => {
    let ignore = false;
    fetch("/api/courses")
      .then((res) => {
        if (!res.ok) throw new Error("Failed to load");
        return res.json();
      })
      .then((data) => { if (!ignore) setCourses(data); })
      .catch((err) => { if (!ignore) setError(err.message); });
    return () => { ignore = true; };  // cleanup
  }, []);

  if (error) return <p>{error}</p>;
  return <ul>{courses.map((c) => <li key={c.id}>{c.title}</li>)}</ul>;
}

The ignore flag prevents setting state after the component unmounts or after a newer request starts.

The dependency array

CodeWhen the effect runs
useEffect(fn)After every render
useEffect(fn, [])Once, after the first render
useEffect(fn, [query])After the first render and whenever query changes

Search that refetches when the query changes

jsx
useEffect(() => {
  const controller = new AbortController();
  fetch(`/api/search?q=${encodeURIComponent(query)}`, { signal: controller.signal })
    .then((r) => r.json())
    .then(setResults)
    .catch(() => {});
  return () => controller.abort();
}, [query]);

Cleanup

Return a function from the effect to undo what it set up. React runs it before the effect runs again and when the component unmounts.

jsx
useEffect(() => {
  const id = setInterval(() => setSeconds((s) => s + 1), 1000);
  return () => clearInterval(id);
}, []);

Common mistakes

  • Missing dependencies: if the effect uses a value, list it in the array. The react-hooks/exhaustive-deps lint rule catches this.
  • Infinite loops: setting state inside an effect that depends on that same state, with no condition.
  • Using an effect for derived data: if a value can be calculated from props or state, calculate it during render instead of storing it in state.
  • Calling hooks conditionally: hooks must be called in the same order on every render, so never call them inside if statements or loops.

Interview questions

  • Why can't hooks be called inside conditions? React tracks hooks by call order; changing the order between renders mixes up their state.
  • What is the difference between props and state? Props are passed in by the parent and are read-only; state is owned and updated by the component.
  • When does a component re-render? When its state changes, when its parent re-renders, or when a context it uses changes.

Next steps

Build a small "course search" app with a search box, loading state and error state. Learn Next.js, TypeScript and AI-assisted UI development in the Frontend Development + AI course.

Master it hands-on

More Design + AI tutorials