search
React star Featured

Getting Started with React Hooks in 2025

Learn how to use React Hooks effectively in your modern React applications with practical examples and best practices.

person By Gautam Sharma
calendar_today December 15, 2024
schedule 4 min read
React JavaScript Hooks Frontend

React Hooks revolutionized how we write React components by allowing us to use state and other React features without writing classes. In this comprehensive guide, we’ll explore the most important hooks and how to use them effectively in 2025.

What Are React Hooks?

Hooks are functions that let you “hook into” React state and lifecycle features from function components. They were introduced in React 16.8 and have become the standard way to write React components.

useState: Managing Component State

The useState hook is the most fundamental hook for managing state in functional 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>
  );
}

Best Practices for useState

Always use the functional update form when the new state depends on the previous state:

// Good
setCount(prevCount => prevCount + 1);

// Avoid
setCount(count + 1);

useEffect: Side Effects Made Easy

The useEffect hook lets you perform side effects in function components. It’s similar to componentDidMount, componentDidUpdate, and componentWillUnmount combined.

import { useState, useEffect } from 'react';

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

  useEffect(() => {
    async function fetchUser() {
      setLoading(true);
      try {
        const response = await fetch(`/api/users/${userId}`);
        const data = await response.json();
        setUser(data);
      } catch (error) {
        console.error('Error fetching user:', error);
      } finally {
        setLoading(false);
      }
    }

    fetchUser();
  }, [userId]);

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

  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

useContext: Sharing Data Across Components

The useContext hook provides a way to pass data through the component tree without manually passing props at every level.

import { createContext, useContext, useState } from 'react';

const ThemeContext = createContext();

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme(prev => prev === 'light' ? 'dark' : 'light');
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

function ThemedButton() {
  const { theme, toggleTheme } = useContext(ThemeContext);

  return (
    <button
      onClick={toggleTheme}
      style={{
        background: theme === 'light' ? '#fff' : '#333',
        color: theme === 'light' ? '#333' : '#fff'
      }}
    >
      Toggle Theme
    </button>
  );
}

Custom Hooks: Reusable Logic

Creating custom hooks allows you to extract component logic into reusable functions.

function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });

  const setValue = (value) => {
    try {
      const valueToStore = value instanceof Function
        ? value(storedValue)
        : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.error(error);
    }
  };

  return [storedValue, setValue];
}

// Usage
function App() {
  const [name, setName] = useLocalStorage('name', 'Guest');

  return (
    <input
      value={name}
      onChange={(e) => setName(e.target.value)}
      placeholder="Enter your name"
    />
  );
}

Common Pitfalls and How to Avoid Them

1. Missing Dependencies

Always include all dependencies in the dependency array of useEffect:

// Bad
useEffect(() => {
  fetchData(userId);
}, []);

// Good
useEffect(() => {
  fetchData(userId);
}, [userId]);

2. Infinite Loops

Be careful not to create infinite loops by updating state inside useEffect without proper dependencies:

// Bad - causes infinite loop
useEffect(() => {
  setCount(count + 1);
});

// Good
useEffect(() => {
  setCount(prevCount => prevCount + 1);
}, []);

Conclusion

React Hooks have made functional components more powerful and easier to work with. By mastering useState, useEffect, and useContext, along with creating custom hooks, you can build modern, maintainable React applications.

Remember to follow the Rules of Hooks:

  • Only call hooks at the top level
  • Only call hooks from React functions
  • Use the ESLint plugin to enforce these rules

Happy coding!

Gautam Sharma

About Gautam Sharma

Full-stack developer and tech blogger sharing coding tutorials and best practices

Related Articles

React

How to integrate jsPDF Library in React to Edit PDF in Browser

Quick guide to using jsPDF in React applications for creating and editing PDF documents directly in the browser.

December 29, 2024
React

QR Codes with React: Quick Implementation

Build QR code scanner and generator in React. Simple setup with react-qr-code and html5-qrcode libraries.

December 31, 2024
HTML

jsPDF Tutorial: Generate PDF in Browser Using HTML & JavaScript (Full Working Example)

Learn to create PDFs directly in the browser with jsPDF. Step-by-step guide with working examples for invoices, tickets, and styled documents.

December 31, 2024