Brain Busters
QuizzesMock TestsGamesLibrary
UpdatesCommunityAboutContactPremium
Brain BustersLearning and Exam Intelligence

A student learning app built for practice discipline, exam simulation, and visible improvement.

Move from reading to execution with guided quizzes, mock tests, performance signals, and current exam updates in one system.

Student-first
Built for focused learners
More than content
Practice, revise, and measure
Progress system
Study with exam-ready feedback

Platform

  • Practice Quizzes
  • Mock Tests
  • Brain Games
  • Learning Library
  • Premium Plans

Resources

  • About Us
  • Exam Updates
  • Community
  • Contact
Weekly Signals

Join the intelligence loop

Receive product updates, study prompts, and exam alerts without the noise.

Location
Azamgarh, Uttar Pradesh, India
Support Line
+91 9161060447
Direct Email
support@brainbusters.in

© 2026 Brain Busters. Practice with intent.

PrivacyTermsSitemap
    Back to library
    Learning article
    Web Development
    JavaScript

    Understanding React Hooks: A Comprehensive Guide with Examples

    React Hooks, introduced in React 16.8, revolutionized how developers manage state and side effects in functional components. They allow you to "hook into" React features like state and lifecycle methods without writing class components. This blog post explores React Hooks in dept

    RC

    R.S. Chauhan

    Brain Busters editorial

    June 13, 2025
    10 min read
    0 likes

    Article snapshot

    Read with revision in mind.

    Use the article to understand the topic, identify weak areas, and move back into quizzes with more context.

    Best for concept review
    Start here before timed practice if the topic feels rusty.
    Revision friendly
    Use the tags and related posts to build a tighter study path around the same theme.
    Discuss and clarify
    Add a comment if you want examples, clarifications, or a follow-up explanation.

    React Hooks, introduced in React 16.8, revolutionized how developers manage state and side effects in functional components. They allow you to "hook into" React features like state and lifecycle methods without writing class components. This blog post explores React Hooks in depth, covering all major hooks with practical, original examples to help you understand their usage.


    What Are React Hooks?

    Hooks are functions that let you use state and other React features in functional components. Before hooks, state and lifecycle methods were only available in class components. Hooks make code more reusable, readable, and easier to maintain by allowing logic to be organized into smaller, composable functions.

    Why Use Hooks?

    • Simpler Syntax: No need for class components or this keyword.
    • Reusable Logic: Custom hooks let you share logic across components.
    • Cleaner Code: Hooks reduce boilerplate and make components easier to test.
    • Functional Paradigm: Aligns with modern JavaScript’s functional programming trends.

    Core React Hooks

    Let’s dive into the core hooks provided by React, with examples for each.

    1. useState

    The useState hook adds state to functional components. It returns an array with the current state and a function to update it.

    Example: Counter App
    A simple counter that increments or decrements a number.

    import React, { useState } from 'react';
    
    function Counter() {
      const [count, setCount] = useState(0);
    
      return (
        <div>
          <h2>Counter: {count}</h2>
          <button onClick={() => setCount(count + 1)}>Increment</button>
          <button onClick={() => setCount(count - 1)}>Decrement</button>
        </div>
      );
    }
    

    Explanation:

    • useState(0) initializes count to 0.
    • setCount updates the state and triggers a re-render.
    • The component re-renders whenever count changes.

    Advanced useState Example: Form Input
    Managing form input state with an object.

    import React, { useState } from 'react';
    
    function UserForm() {
      const [form, setForm] = useState({ name: '', email: '' });
    
      const handleChange = (e) => {
        setForm({ ...form, [e.target.name]: e.target.value });
      };
    
      return (
        <div>
          <input
            type="text"
            name="name"
            value={form.name}
            onChange={handleChange}
            placeholder="Enter name"
          />
          <input
            type="email"
            name="email"
            value={form.email}
            onChange={handleChange}
            placeholder="Enter email"
          />
          <p>Name: {form.name}</p>
          <p>Email: {form.email}</p>
        </div>
      );
    }
    

    Explanation:

    • useState holds an object with name and email.
    • The spread operator (...form) preserves existing state while updating specific fields.

    2. useEffect

    The useEffect hook handles side effects, such as fetching data, subscriptions, or DOM manipulation. It runs after every render by default but can be controlled with a dependency array.

    Example: Fetching Data
    Fetch a list of users from a mock API.

    import React, { useState, useEffect } from 'react';
    
    function UserList() {
      const [users, setUsers] = useState([]);
      const [loading, setLoading] = useState(true);
    
      useEffect(() => {
        fetch('https://jsonplaceholder.typicode.com/users')
          .then((response) => response.json())
          .then((data) => {
            setUsers(data);
            setLoading(false);
          });
      }, []); // Empty dependency array: runs once on mount
    
      if (loading) return <p>Loading...</p>;
    
      return (
        <ul>
          {users.map((user) => (
            <li key={user.id}>{user.name}</li>
          ))}
        </ul>
      );
    }
    

    Explanation:

    • useEffect runs the fetch call when the component mounts.
    • The empty dependency array ([]) ensures it runs only once.
    • setUsers updates the state with fetched data, and setLoading toggles the loading state.

    Advanced useEffect Example: Window Resize Listener
    Track the browser window’s width.

    import React, { useState, useEffect } from 'react';
    
    function WindowSize() {
      const [windowWidth, setWindowWidth] = useState(window.innerWidth);
    
      useEffect(() => {
        const handleResize = () => setWindowWidth(window.innerWidth);
        window.addEventListener('resize', handleResize);
        return () => window.removeEventListener('resize', handleResize); // Cleanup
      }, []); // Empty dependency array
    
      return <p>Window Width: {windowWidth}px</p>;
    }
    

    Explanation:

    • useEffect adds an event listener for window resizing.
    • The cleanup function (returned by useEffect) removes the listener to prevent memory leaks.
    • The dependency array ensures the effect runs only on mount and unmount.

    3. useContext

    The useContext hook accesses React’s context API, allowing you to share data without prop drilling.

    Example: Theme Switcher
    Toggle between light and dark themes using context.

    import React, { useContext, useState } from 'react';
    
    // Create Context
    const ThemeContext = React.createContext();
    
    function ThemeProvider({ children }) {
      const [theme, setTheme] = useState('light');
    
      const toggleTheme = () => {
        setTheme(theme === 'light' ? 'dark' : 'light');
      };
    
      return (
        <ThemeContext.Provider value={{ theme, toggleTheme }}>
          {children}
        </ThemeContext.Provider>
      );
    }
    
    function ThemeComponent() {
      const { theme, toggleTheme } = useContext(ThemeContext);
    
      return (
        <div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}>
          <p>Current Theme: {theme}</p>
          <button onClick={toggleTheme}>Toggle Theme</button>
        </div>
      );
    }
    
    function App() {
      return (
        <ThemeProvider>
          <ThemeComponent />
        </ThemeProvider>
      );
    }
    

    Explanation:

    • ThemeContext holds the theme state and toggleTheme function.
    • useContext(ThemeContext) provides access to the context values in ThemeComponent.
    • The component dynamically updates styles based on the theme.

    4. useReducer

    The useReducer hook manages complex state logic, similar to Redux. It’s useful when state transitions involve multiple actions or conditions.

    Example: Todo List
    A simple todo list with add and remove functionality.

    import React, { useReducer } from 'react';
    
    const initialState = { todos: [] };
    
    function reducer(state, action) {
      switch (action.type) {
        case 'ADD_TODO':
          return { todos: [...state.todos, action.payload] };
        case 'REMOVE_TODO':
          return { todos: state.todos.filter((_, index) => index !== action.payload) };
        default:
          return state;
      }
    }
    
    function TodoList() {
      const [state, dispatch] = useReducer(reducer, initialState);
      const [input, setInput] = useState('');
    
      const addTodo = () => {
        if (input.trim()) {
          dispatch({ type: 'ADD_TODO', payload: input });
          setInput('');
        }
      };
    
      return (
        <div>
          <input
            type="text"
            value={input}
            onChange={(e) => setInput(e.target.value)}
            placeholder="Add a todo"
          />
          <button onClick={addTodo}>Add</button>
          <ul>
            {state.todos.map((todo, index) => (
              <li key={index}>
                {todo} <button onClick={() => dispatch({ type: 'REMOVE_TODO', payload: index })}>Remove</button>
              </li>
            ))}
          </ul>
        </div>
      );
    }
    

    Explanation:

    • useReducer manages the todos array with a reducer function.
    • Actions (ADD_TODO, REMOVE_TODO) define state changes.
    • dispatch triggers state updates based on action types.

    5. useCallback

    The useCallback hook memoizes functions to prevent unnecessary re-creations, improving performance in scenarios involving child components.

    Example: Memoized Callback
    Pass a memoized function to a child component.

    import React, { useState, useCallback } from 'react';
    
    function Button({ onClick, label }) {
      console.log(`${label} Button rendered`);
      return <button onClick={onClick}>{label}</button>;
    }
    
    function CounterApp() {
      const [count, setCount] = useState(0);
    
      const increment = useCallback(() => {
        setCount((prev) => prev + 1);
      }, []); // Empty dependency array: memoized forever
    
      return (
        <div>
          <p>Count: {count}</p>
          <Button onClick={increment} label="Increment" />
        </div>
      );
    }
    

    Explanation:

    • useCallback memoizes the increment function.
    • Without useCallback, the Button component would re-render unnecessarily on every state change.
    • The dependency array ([]) ensures the function is only created once.

    6. useMemo

    The useMemo hook memoizes expensive computations, re-running them only when dependencies change.

    Example: Expensive Calculation
    Calculate the sum of numbers in a range.

    import React, { useState, useMemo } from 'react';
    
    function SumCalculator() {
      const [range, setRange] = useState(1000);
      const [otherState, setOtherState] = useState(0);
    
      const sum = useMemo(() => {
        console.log('Calculating sum...');
        let total = 0;
        for (let i = 1; i <= range; i++) {
          total += i;
        }
        return total;
      }, [range]); // Only recalculate if range changes
    
      return (
        <div>
          <p>Sum of numbers up to {range}: {sum}</p>
          <input
            type="number"
            value={range}
            onChange={(e) => setRange(Number(e.target.value))}
          />
          <button onClick={() => setOtherState(otherState + 1)}>
            Other State: {otherState}
          </button>
        </div>
      );
    }
    

    Explanation:

    • useMemo caches the sum calculation.
    • The calculation only runs when range changes, not when otherState updates.
    • This improves performance for computationally expensive operations.

    7. useRef

    The useRef hook creates a mutable reference that persists across renders. It’s commonly used for DOM access or storing values without triggering re-renders.

    Example: Focus Input
    Focus an input field on button click.

    import React, { useRef } from 'react';
    
    function FocusInput() {
      const inputRef = useRef(null);
    
      const handleClick = () => {
        inputRef.current.focus();
      };
    
      return (
        <div>
          <input type="text" ref={inputRef} placeholder="Type here" />
          <button onClick={handleClick}>Focus Input</button>
        </div>
      );
    }
    

    Explanation:

    • useRef creates a reference to the input element.
    • inputRef.current accesses the DOM node to call focus().

    Advanced useRef Example: Tracking Previous State
    Track the previous value of a state.

    import React, { useState, useRef, useEffect } from 'react';
    
    function PreviousValue() {
      const [count, setCount] = useState(0);
      const prevCountRef = useRef();
    
      useEffect(() => {
        prevCountRef.current = count; // Update ref after each render
      }, [count]);
    
      return (
        <div>
          <p>Current Count: {count}</p>
          <p>Previous Count: {prevCountRef.current}</p>
          <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
      );
    }
    

    Explanation:

    • useRef stores the previous count value.
    • useEffect updates the ref after each render, preserving the previous state.

    8. useLayoutEffect

    The useLayoutEffect hook is similar to useEffect but runs synchronously after DOM updates, before the browser paints. It’s useful for DOM measurements.

    Example: Measuring Element Size
    Measure the dimensions of a div.

    import React, { useState, useLayoutEffect, useRef } from 'react';
    
    function ElementSize() {
      const [size, setSize] = useState({ width: 0, height: 0 });
      const divRef = useRef(null);
    
      useLayoutEffect(() => {
        const rect = divRef.current.getBoundingClientRect();
        setSize({ width: rect.width, height: rect.height });
      }, []);
    
      return (
        <div>
          <div ref={divRef} style={{ width: '200px', height: '100px', background: 'lightblue' }}>
            Measure me!
          </div>
          <p>Width: {size.width}px, Height: {size.height}px</p>
        </div>
      );
    }
    

    Explanation:

    • useLayoutEffect measures the div’s size immediately after DOM updates.
    • It’s synchronous, ensuring accurate measurements before rendering.

    9. useImperativeHandle

    The useImperativeHandle hook customizes the instance value exposed to parent components when using ref. It’s used with forwardRef.

    Example: Custom Input Focus
    Expose a custom focus method to the parent.

    import React, { useRef, useImperativeHandle, forwardRef } from 'react';
    
    const CustomInput = forwardRef((props, ref) => {
      const inputRef = useRef();
    
      useImperativeHandle(ref, () => ({
        customFocus: () => {
          inputRef.current.focus();
          inputRef.current.value = 'Custom Focus!';
        },
      }));
    
      return <input ref={inputRef} placeholder="Custom input" />;
    });
    
    function App() {
      const inputRef = useRef();
    
      return (
        <div>
          <CustomInput ref={inputRef} />
          <button onClick={() => inputRef.current.customFocus()}>
            Trigger Custom Focus
          </button>
        </div>
      );
    }
    

    Explanation:

    • useImperativeHandle exposes a customFocus method to the parent.
    • The parent can call customFocus via the ref, which focuses the input and sets its value.

    10. useDebugValue

    The useDebugValue hook labels custom hooks in React DevTools, improving debugging.

    Example: Custom Hook with Debug Value
    A custom hook to track window size.

    import React, { useState, useEffect, useDebugValue } from 'react';
    
    function useWindowSize() {
      const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight });
    
      useEffect(() => {
        const handleResize = () => setSize({ width: window.innerWidth, height: window.innerHeight });
        window.addEventListener('resize', handleResize);
        return () => window.removeEventListener('resize', handleResize);
      }, []);
    
      useDebugValue(`Width: ${size.width}, Height: ${size.height}`);
    
      return size;
    }
    
    function WindowSizeDisplay() {
      const { width, height } = useWindowSize();
    
      return (
        <p>
          Window Size: {width}x{height}
        </p>
      );
    }
    

    Explanation:

    • useDebugValue displays the window size in React DevTools for the useWindowSize hook.
    • This helps developers debug custom hooks.

    Custom Hooks

    Custom hooks are reusable functions that encapsulate logic using built-in hooks. They follow the naming convention useSomething.

    Example: useToggle
    A custom hook to toggle a boolean state.

    import React, { useState } from 'react';
    
    function useToggle(initialValue = false) {
      const [value, setValue] = useState(initialValue);
    
      const toggle = () => setValue(!value);
    
      return [value, toggle];
    }
    
    function ToggleComponent() {
      const [isOn, toggle] = useToggle(false);
    
      return (
        <div>
          <p>Toggle is {isOn ? 'ON' : 'OFF'}</p>
          <button onClick={toggle}>Toggle</button>
        </div>
      );
    }
    

    Explanation:

    • useToggle encapsulates toggle logic using useState.
    • It returns the current state and a toggle function, reusable across components.

    Rules of Hooks

    To ensure hooks work correctly, follow these rules:

    1. Only Call Hooks at the Top Level: Don’t call hooks inside loops, conditions, or nested functions.
    2. Only Call Hooks from React Functions: Use hooks in functional components or custom hooks, not regular JavaScript functions.
    3. Use the ESLint plugin eslint-plugin-react-hooks to enforce these rules.

    Example of Incorrect Usage:

    function BadComponent() {
      if (true) {
        const [state, setState] = useState(0); // Error: Hook in condition
      }
    }
    

    Correct Usage:

    function GoodComponent() {
      const [state, setState] = useState(0); // Top-level hook
    }
    

    Best Practices

    • Keep Hooks Simple: Break complex logic into custom hooks.
    • Use Dependency Arrays Wisely: Specify all dependencies in useEffect and useMemo to avoid bugs.
    • Clean Up Effects: Return cleanup functions in useEffect to prevent memory leaks.
    • Memoize When Necessary: Use useCallback and useMemo only when performance is an issue.
    • Debug with useDebugValue: Label custom hooks for better debugging.

    Conclusion

    React Hooks simplify state management and side effects in functional components, making React code more modular and maintainable. By mastering hooks like useState, useEffect, useContext, and others, you can build efficient, reusable components. Custom hooks take this further by encapsulating logic for reuse across your application.

    Try experimenting with the examples provided to deepen your understanding. Happy coding!

    Topics and tags

    Continue from this topic

    Practice next

    Related quizzes

    JavaScript Variable

    In JavaScript, a variable is a container that stores data values. Think of it like a box that you can put different things in. These "things" could be numbers, text, or even more complex information.

    Discussion

    Comments (0)

    Keep comments specific so learners can benefit from the discussion.

    No comments yet.

    Start the discussion with a question or a study insight.

    Quick facts

    Use this article as

    Primary topicWeb Development
    Read time10 minutes
    Comments0
    UpdatedJune 13, 2025

    Author

    RC
    R.S. Chauhan
    Published June 13, 2025

    Tagged with

    javascript
    web development
    React
    Browse library