REACT Hooks Overview

React Hooks are functions introduced in React 16.8 that allow developers to use state and lifecycle features in functional components. They simplify code and eliminate the need for class components in many scenarios.

What Are Hooks?

Hooks are special functions that let you “hook into” React features, like state and lifecycle methods, without writing a class.

Why Use Hooks?

  1. Simplify Components: Replace complex class components with cleaner functional components.
  2. Reuse Logic: Share stateful logic between components using custom hooks.
  3. Easier to Read and Test: Functional components with hooks are more concise and easier to test.

Basic Rules of Hooks

  1. Only Call Hooks at the Top Level
    • Do not call hooks inside loops, conditions, or nested functions.
    • Always call hooks at the top level of your React function.
  2. Only Call Hooks in React Functions
    • Use hooks in functional components or within custom hooks.

Commonly Used Built-In Hooks

1. useState

  • Allows you to add state to a functional component.
  • Returns the current state and a function to update it.
import React, { useState } from "react";

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

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
    );
}

export default Counter;

Try It Now

 

2. useEffect

  • Performs side effects in functional components (e.g., fetching data, updating the DOM).
  • Runs after the render phase by default.
import React, { useState, useEffect } from "react";

function Timer() {
    const [seconds, setSeconds] = useState(0);

    useEffect(() => {
        const interval = setInterval(() => {
            setSeconds((prev) => prev + 1);
        }, 1000);

        return () => clearInterval(interval); // Cleanup on unmount
    }, []);

    return <p>Time: {seconds} seconds</p>;
}

export default Timer;

Try It Now

 

3. useContext

  • Allows components to consume a React context without using Context.Consumer.
import React, { createContext, useContext } from "react";

const ThemeContext = createContext("light");

function ThemeButton() {
    const theme = useContext(ThemeContext);
    return <button>{theme} Theme</button>;
}

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

export default App;

Try It Now

 

4. useRef

  • Returns a mutable object that persists between renders.
  • Commonly used to access DOM elements or store state that doesn’t trigger re-renders.
import React, { useRef } from "react";

function FocusInput() {
    const inputRef = useRef();

    const focusInput = () => {
        inputRef.current.focus();
    };

    return (
        <div>
            <input ref={inputRef} type="text" />
            <button onClick={focusInput}>Focus Input</button>
        </div>
    );
}

export default FocusInput;

Try It Now

5. useReducer

  • An alternative to useState for managing more complex state logic.
import React, { useReducer } from "react";

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

function Counter() {
    const [state, dispatch] = useReducer(reducer, { count: 0 });

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

export default Counter;

Try It Now

 

Advanced Hooks

1. useMemo

  • Optimizes performance by memoizing expensive calculations.
import React, { useState, useMemo } from "react";

function ExpensiveCalculation({ num }) {
    const result = useMemo(() => {
        console.log("Calculating...");
        return num ** 2;
    }, [num]);

    return <p>Square: {result}</p>;
}

export default ExpensiveCalculation;

Try It Now

2. useCallback

  • Memoizes functions to prevent unnecessary re-creation.
import React, { useState, useCallback } from "react";

function Button({ handleClick }) {
    return <button onClick={handleClick}>Click Me</button>;
}

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

    const handleIncrement = useCallback(() => {
        setCount((prev) => prev + 1);
    }, []);

    return (
        <div>
            <p>Count: {count}</p>
            <Button handleClick={handleIncrement} />
        </div>
    );
}

export default App;

Try It Now

 

3. Custom Hooks

  • Create reusable logic by combining hooks into custom functions.
import React, { useState } from "react";

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

    const increment = () => setCount((prev) => prev + 1);
    const decrement = () => setCount((prev) => prev - 1);

    return { count, increment, decrement };
}

function Counter() {
    const { count, increment, decrement } = useCounter();

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

export default Counter;

Try It Now

Hooks Best Practices

  1. Keep Hooks Simple: Break complex logic into smaller custom hooks.
  2. Use Dependencies Correctly: Always provide a dependency array in useEffect, useCallback, or useMemo.
  3. Avoid Overusing Hooks: Don’t use hooks unnecessarily; keep the component simple.
  4. Test Hooks: Write unit tests for custom hooks to ensure correctness.

React Hooks empower developers to build cleaner, more efficient, and reusable functional components.