React Hooks Deep Dive

Master useState, useEffect, useContext, and custom hooks. Learn when and how to use each hook effectively in your applications.

Hooks let you use state and other React features in functional components. They were introduced in React 16.8 and have become the standard way to build React applications.

useState

Manages local component state. Returns a stateful value and a function to update it.

useEffect

Handles side effects like data fetching, subscriptions, and DOM manipulation. Runs after render and can clean up before the component unmounts.

useContext

Accesses context values without prop drilling. Useful for sharing global data like themes or user authentication.

useRef

Creates a mutable reference that persists across renders. Commonly used for accessing DOM elements or storing values that shouldn't trigger re-renders.

Custom Hooks

Extract and reuse stateful logic between components. Custom hooks are functions that use other hooks and follow the naming convention "use-".

Code Examples

useState Examples

Counter.jsx
import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  // Simple update
  const increment = () => setCount(count + 1);

  // Functional update (when new state depends on old)
  const decrement = () => setCount(prev => prev - 1);

  // Object state
  const [user, setUser] = useState({ name: '', email: '' });
  const updateName = (name) => {
    setUser(prev => ({ ...prev, name }));
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  );
}

useEffect Patterns

DataFetcher.jsx
import { useState, useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

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

    async function fetchUser() {
      setLoading(true);
      try {
        const res = await fetch(`/api/users/${userId}`);
        const data = await res.json();
        if (!cancelled) {
          setUser(data);
        }
      } finally {
        if (!cancelled) {
          setLoading(false);
        }
      }
    }

    fetchUser();

    // Cleanup function
    return () => {
      cancelled = true;
    };
  }, [userId]); // Re-run when userId changes

  if (loading) return <p>Loading...</p>;
  if (!user) return <p>User not found</p>;

  return <h1>{user.name}</h1>;
}

Custom Hook

useLocalStorage.js
import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  // Initialize state from localStorage or use initialValue
  const [value, setValue] = useState(() => {
    const stored = localStorage.getItem(key);
    return stored ? JSON.parse(stored) : initialValue;
  });

  // Update localStorage when value changes
  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
}

// Usage
function Settings() {
  const [theme, setTheme] = useLocalStorage('theme', 'dark');

  return (
    <select value={theme} onChange={e => setTheme(e.target.value)}>
      <option value="light">Light</option>
      <option value="dark">Dark</option>
    </select>
  );
}

Frequently Asked Questions

Why do hooks have rules like calling them at the top level?

React relies on the order of hook calls to associate state with the correct hook. Calling hooks inside conditions or loops would break this order between renders, causing bugs.

When should I use useRef vs useState?

Use useState when the value should trigger a re-render when it changes. Use useRef for values that need to persist but shouldn't cause re-renders, like DOM references or timers.

How do I avoid infinite loops in useEffect?

Ensure your dependency array is correct. If an effect updates a value that's in its dependencies, you'll get an infinite loop. Use functional updates or move the value outside the effect.

Need React Help?

Slashdev.io builds production-ready React applications for businesses of all sizes.

Get in Touch