React Hooks

React Hooks

About this quiz

This quiz about React Hooks features 10 questions. It was generated by one of our users February 12, 2026.

React Hooks: Revolutionizing Function Components

React Hooks fundamentally transformed how developers write React applications when they were introduced in version 16.8. Before Hooks, function components were considered "stateless" and could only render UI based on props, while class components held the monopoly on state management and lifecycle methods. Hooks shattered this limitation by allowing function components to "hook into" React's powerful features like state, context, and side effects. This paradigm shift not only simplified component logic but also made code more reusable, testable, and easier to understand.

The beauty of Hooks lies in their elegant simplicity and composability. Built-in hooks like useState bring stateful logic to function components, while useEffect handles side effects and replaces multiple lifecycle methods with a single, intuitive API. useContext makes consuming context data effortless, and useReducer provides a Redux-like state management pattern for complex scenarios. Beyond the built-in options, developers can create custom hooks to encapsulate and share stateful logic across components, promoting the DRY (Don't Repeat Yourself) principle like never before.

Today, Hooks have become the preferred approach for React development, with many considering them essential knowledge for any React developer. They've enabled cleaner component hierarchies, reduced boilerplate code, and made React applications more performant through better optimization opportunities. Ready to test your understanding of this game-changing feature?

React Hooks: Complete Study Guide ๐ŸŽฃ

Table of Contents

Introduction to React Hooks

What is the Primary Purpose of React Hooks? ๐ŸŽฏ

React Hooks were introduced in React 16.8 to solve several fundamental problems:

**Primary Purposes:**
  1. Enable State in Functional Components

    // Before Hooks (Class Component)
    class Counter extends React.Component {
      constructor(props) {
        super(props);
        this.state = { count: 0 };
      }
      
      render() {
        return <div>{this.state.count}</div>;
      }
    }
    
    // After Hooks (Functional Component)
    function Counter() {
      const [count, setCount] = useState(0);
      return <div>{count}</div>;
    }
    
  2. Reuse Stateful Logic Between Components

    // Custom Hook for reusable logic
    function useCounter(initialValue = 0) {
      const [count, setCount] = useState(initialValue);
      
      const increment = () => setCount(count + 1);
      const decrement = () => setCount(count - 1);
      
      return { count, increment, decrement };
    }
    
    // Use in multiple components
    function ComponentA() {
      const { count, increment } = useCounter(10);
      return <button onClick={increment}>{count}</button>;
    }
    
  3. Simplify Component Logic

    • Eliminate complex lifecycle methods
    • Reduce component hierarchy
    • Make code more readable and maintainable
  4. Better Developer Experience

    • Easier testing
    • Better code splitting
    • Improved performance optimizations

Core Hook Concepts

The Rules of Hooks ๐Ÿ“‹

โš ๏ธ Critical: Hooks must follow these rules to work correctly!

  1. Only call Hooks at the top level
  2. Only call Hooks from React functions

State Management with useState

Which Hook is Used to Manage State in a Functional Component? ๐Ÿ”„

The useState hook is the primary hook for managing state in functional components.

**Basic Syntax:**
const [state, setState] = useState(initialValue);
**Examples:**
import React, { useState } from 'react';

function UserProfile() {
  // String state
  const [name, setName] = useState('');
  
  // Number state
  const [age, setAge] = useState(0);
  
  // Boolean state
  const [isActive, setIsActive] = useState(false);
  
  // Object state
  const [user, setUser] = useState({
    email: '',
    preferences: {}
  });
  
  // Array state
  const [items, setItems] = useState([]);
  
  return (
    <div>
      <input 
        value={name} 
        onChange={(e) => setName(e.target.value)} 
      />
      <button onClick={() => setAge(age + 1)}>
        Age: {age}
      </button>
    </div>
  );
}
What is the Correct Way to Update State When the New State Depends on the Previous State? ๐Ÿ”„

When updating state based on the previous state, always use the functional update pattern:

**โœ… Correct Way:**
function Counter() {
  const [count, setCount] = useState(0);
  
  // Functional update - CORRECT
  const increment = () => {
    setCount(prevCount => prevCount + 1);
  };
  
  // Multiple updates work correctly
  const incrementTwice = () => {
    setCount(prevCount => prevCount + 1);
    setCount(prevCount => prevCount + 1); // This works!
  };
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>+1</button>
      <button onClick={incrementTwice}>+2</button>
    </div>
  );
}
**โŒ Incorrect Way:**
function Counter() {
  const [count, setCount] = useState(0);
  
  // Direct reference - PROBLEMATIC
  const increment = () => {
    setCount(count + 1); // May use stale state
  };
  
  // Multiple updates won't work as expected
  const incrementTwice = () => {
    setCount(count + 1);
    setCount(count + 1); // Both use same 'count' value!
  };
}
**Complex State Updates:**
function ShoppingCart() {
  const [cart, setCart] = useState([]);
  
  const addItem = (newItem) => {
    setCart(prevCart => [...prevCart, newItem]);
  };
  
  const updateQuantity = (id, quantity) => {
    setCart(prevCart => 
      prevCart.map(item => 
        item.id === id 
          ? { ...item, quantity }
          : item
      )
    );
  };
  
  const removeItem = (id) => {
    setCart(prevCart => 
      prevCart.filter(item => item.id !== id)
    );
  };
}

Side Effects with useEffect

When Does the useEffect Hook Run by Default? โฐ

By default, useEffect runs after every render (both initial render and updates).

function MyComponent() {
  const [count, setCount] = useState(0);
  
  // Runs after every render
  useEffect(() => {
    console.log('Component rendered!');
    document.title = `Count: ${count}`;
  });
  
  return (
    <button onClick={() => setCount(count + 1)}>
      {count}
    </button>
  );
}
What Does an Empty Dependency Array [] in useEffect Indicate? ๐ŸŽฏ

An empty dependency array [] means the effect runs only once after the initial render (similar to componentDidMount).

function DataFetcher() {
  const [data, setData] = useState(null);
  
  // Runs only once after initial render
  useEffect(() => {
    async function fetchData() {
      const response = await fetch('/api/data');
      const result = await response.json();
      setData(result);
    }
    
    fetchData();
  }, []); // Empty dependency array
  
  return <div>{data ? data.title : 'Loading...'}</div>;
}
**useEffect Patterns:**
function EffectExamples() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('');
  
  // 1. No dependency array - runs after every render
  useEffect(() => {
    console.log('After every render');
  });
  
  // 2. Empty dependency array - runs once
  useEffect(() => {
    console.log('Only on mount');
  }, []);
  
  // 3. Specific dependencies - runs when dependencies change
  useEffect(() => {
    console.log('When count changes');
  }, [count]);
  
  // 4. Multiple dependencies
  useEffect(() => {
    console.log('When count or name changes');
  }, [count, name]);
}
What is the Purpose of the Cleanup Function in useEffect? ๐Ÿงน

The cleanup function prevents memory leaks and unwanted side effects by cleaning up subscriptions, timers, and event listeners.

**Basic Cleanup Pattern:**
useEffect(() => {
  // Setup
  const subscription = someAPI.subscribe();
  
  // Cleanup function
  return () => {
    subscription.unsubscribe();
  };
}, []);
**Real-world Examples:**
function TimerComponent() {
  const [seconds, setSeconds] = useState(0);
  
  useEffect(() => {
    // Setup timer
    const interval = setInterval(() => {
      setSeconds(prev => prev + 1);
    }, 1000);
    
    // Cleanup timer
    return () => {
      clearInterval(interval);
    };
  }, []);
  
  return <div>Seconds: {seconds}</div>;
}

function WindowSizeTracker() {
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight
  });
  
  useEffect(() => {
    // Setup event listener
    function handleResize() {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight
      });
    }
    
    window.addEventListener('resize', handleResize);
    
    // Cleanup event listener
    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []);
  
  return <div>{windowSize.width} x {windowSize.height}</div>;
}

function WebSocketComponent() {
  const [messages, setMessages] = useState([]);
  
  useEffect(() => {
    // Setup WebSocket connection
    const ws = new WebSocket('wss://example.com/socket');
    
    ws.onmessage = (event) => {
      setMessages(prev => [...prev, event.data]);
    };
    
    // Cleanup WebSocket connection
    return () => {
      ws.close();
    };
  }, []);
  
  return (
    <ul>
      {messages.map((msg, index) => (
        <li key={index}>{msg}</li>
      ))}
    </ul>
  );
}

Context with useContext

Which Hook Would You Use to Access a React Context Value? ๐ŸŒ

The useContext hook is used to access React context values in functional components.

**Setting Up Context:**
// 1. Create Context
const ThemeContext = React.createContext();
const UserContext = React.createContext();

// 2. Create Provider Component
function App() {
  const [theme, setTheme] = useState('light');
  const [user, setUser] = useState(null);
  
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <UserContext.Provider value={{ user, setUser }}>
        <Header />
        <MainContent />
      </UserContext.Provider>
    </ThemeContext.Provider>
  );
}