React JSApril 2, 2024·10 min read

Complete Guide to React Hooks — useState, useEffect & Beyond

A comprehensive guide to React Hooks — learn how to use useState, useEffect, useContext, useReducer, and create custom hooks from scratch.

AB
Abhishek BhanotFull Stack Developer · WordPress & Next.js Expert

React Hooks revolutionized how we write React components. Introduced in React 16.8, hooks let you use state and other React features in functional components. Let's dive deep into the most important ones.

What Are React Hooks?

Hooks are functions that let you "hook into" React state and lifecycle features from function components. They were created to avoid the complexity of class components and make code reuse easier.

1. useState — Managing Local State

The most commonly used hook. It returns a state variable and a function to update it.

import { useState } from 'react';

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

Pro Tip: When the new state depends on the previous state, always use the functional update form: setCount(prev => prev + 1).

2. useEffect — Side Effects & Lifecycle

useEffect handles side effects like fetching data, subscribing to events, or updating the DOM.

import { useState, useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    // Runs after every render where userId changes
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => setUser(data));
    
    // Cleanup function (like componentWillUnmount)
    return () => {
      // Cancel requests, clear timeouts here
    };
  }, [userId]); // Dependency array
}

3. useContext — Avoiding Prop Drilling

Share data across components without passing props at every level.

const ThemeContext = React.createContext('light');

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return <button className={theme}>Click me</button>;
}

4. useReducer — Complex State Logic

A great alternative to useState when state logic is complex.

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment': return { count: state.count + 1 };
    case 'decrement': return { count: state.count - 1 };
    case 'reset': return initialState;
    default: throw new Error('Unknown action');
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
    </>
  );
}

5. useMemo & useCallback — Performance Optimization

// useMemo - memoize computed values
const expensiveResult = useMemo(() => {
  return heavyComputation(data);
}, [data]);

// useCallback - memoize functions
const handleClick = useCallback(() => {
  doSomething(id);
}, [id]);

6. Building Custom Hooks

Custom hooks let you extract component logic into reusable functions.

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(data => { setData(data); setLoading(false); })
      .catch(err => { setError(err); setLoading(false); });
  }, [url]);
  
  return { data, loading, error };
}

// Usage
function Posts() {
  const { data, loading, error } = useFetch('/api/posts');
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error!</p>;
  return <ul>{data.map(post => <li key={post.id}>{post.title}</li>)}</ul>;
}

Rules of Hooks

  1. Only call hooks at the top level (not inside loops, conditions, or nested functions)
  2. Only call hooks from React function components or custom hooks
  3. Custom hooks must start with "use"

Conclusion

React Hooks make your code more readable, reusable, and maintainable. Start with useState and useEffect, then gradually explore useContext, useReducer, and custom hooks as your app grows.

AB

Abhishek Bhanot

Full Stack Developer with 7+ years of experience in WordPress, Next.js, React, PHP, and modern web technologies. Helped 200+ clients worldwide build high-performance websites.

Hire Me🛍 PouchCraft.in

More Articles

JavaScript

10 JavaScript Tips & Tricks Every Developer Should Know in 2024

8 min read
WordPress

WordPress Complete Beginners Guide — Build Your Site in 2024

12 min read
WooCommerce

WooCommerce Complete Setup Guide — Launch Your Online Store

11 min read