Home About Skills Products Work
Projects Services Experience
Learn
Tutorials Courses Blogs Resources
Contact
Blog · JavaScript

React Hooks Explained: useState, useEffect, and Beyond

React Hooks Explained: useState, useEffect, and Beyond

Hooks let function components hold state and side effects — capabilities that used to require a class component. useState and useEffect cover the vast majority of real-world component logic; here's exactly how each works and where developers commonly trip up.

useState: Component State

function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

Calling setCount doesn't mutate count in place — it schedules a re-render with the new value. This is why count inside a single render is always the value from THAT render, never magically "current."

The Stale State Trap

function increment() {
  setCount(count + 1);
  setCount(count + 1); // still only +1 total — both read the SAME stale `count`
}

// Fix: use the updater function form when the new value depends on the old one
function increment() {
  setCount(c => c + 1);
  setCount(c => c + 1); // now correctly +2
}

useEffect: Side Effects

useEffect(() => {
  const timer = setInterval(() => console.log('tick'), 1000);
  return () => clearInterval(timer); // cleanup — runs before the next effect or on unmount
}, []); // empty array = run once, on mount

The dependency array is the part everyone gets wrong at first: it's not "when to run this," it's "these are the reactive values this effect reads — re-run whenever any of them change." Omitting a value the effect actually uses is the #1 cause of bugs where a component doesn't update when you'd expect it to.

Data Fetching with useEffect

useEffect(() => {
  let cancelled = false;

  fetch(`/api/users/${userId}`)
    .then(res => res.json())
    .then(data => { if (!cancelled) setUser(data); });

  return () => { cancelled = true; }; // avoid setting state after unmount
}, [userId]);

Beyond the Basics: useRef and useContext

const inputRef = useRef(null);
useEffect(() => inputRef.current.focus(), []);
// 

useRef holds a mutable value that doesn't trigger a re-render when changed — perfect for DOM references or any value you need to track without it affecting rendering. useContext reads from a Context Provider higher in the tree, avoiding prop-drilling through components that don't otherwise need the data.

Master these four hooks and you can build the overwhelming majority of real React components — everything else (useReducer, useMemo, custom hooks) is a variation on the same core ideas.

JavaScript Fundamentals Every Beginner Should Master

JavaScript Fundamentals Every Beginner Should Master

Variables, functions, arrays, objects, and the DOM — the plain JavaScript every framework is built on top of.

Async/Await and Promises in JavaScript: A Practical Guide

How Promises actually work, why async/await is just readable syntax on top of them, and the parallel-fetching mistake almost everyone makes.

Modern JavaScript (ES6+) Features You Should Be Using

Modern JavaScript (ES6+) Features You Should Be Using

Template literals, destructuring, optional chaining, and modules — the JavaScript you actually see in every modern codebase.

Esc