Blog Post

React Hooks: useState and useEffect Explained

Essential hooks for modern React development

React Hooks revolutionized function components by providing state and lifecycle features previously exclusive to class components. Understanding these two fundamental hooks is essential for modern React development.

useState: Managing Component State

useState adds state to function components:

import { useState } from 'react';

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

Key points:

  • Returns array: [currentValue, updaterFunction]
  • Initial value passed to useState()
  • Updating state triggers re-render
  • State updates are asynchronous

Multiple State Variables

Declare multiple independent state variables:

function UserForm() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [age, setAge] = useState(0);
  
  // Handle each independently
}

useEffect: Side Effects and Lifecycle

useEffect handles side effects—data fetching, subscriptions, manual DOM updates:

import { useState, useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => setUser(data));
  }, [userId]); // Dependency array
  
  return <div>{user?.name}</div>;
}

Dependency Arrays

The second argument controls when effects run:

useEffect(() => {
  // Runs after every render
});

useEffect(() => {
  // Runs once after initial render
}, []);

useEffect(() => {
  // Runs when dependency changes
}, [dependency]);

Cleanup Functions

Return a function to clean up side effects:

useEffect(() => {
  const timer = setInterval(() => {
    console.log('tick');
  }, 1000);
  
  return () => clearInterval(timer); // Cleanup
}, []);

Common Mistakes

  1. Missing dependencies: Always include variables used inside effects
  2. Infinite loops: Updating state without proper dependencies
  3. Not cleaning up: Leaving subscriptions or timers running
// Infinite loop - BAD
useEffect(() => {
  setCount(count + 1); // Updates every render
});

// Correct
useEffect(() => {
  setCount(c => c + 1); // Runs once
}, []);

Mastering these two hooks provides the foundation for all other React hooks and modern component patterns.