DEV Community

Cover image for Most Commonly Used React Hooks Comparison: When to Use Which Hook?
Shefali
Shefali

Posted on • Originally published at shefali.dev

Most Commonly Used React Hooks Comparison: When to Use Which Hook?

If you’re looking for a clear React hooks comparison, you’ve come to the right place. React hooks simplify state and side effect management, but knowing which hook to use and when can be confusing.

In this post, I’ll share a most commonly used React hook comparison so you’ll know exactly when to use each one.

Before we get started, don’t forget to subscribe to my newsletter!
Get the latest tips, tools, and resources to level up your web development skills delivered straight to your inbox. Subscribe here!

Now, let’s jump right into it!

useState vs. useReducer: Choosing the Right React Hook for State

Use useState when:

  • The state is simple, and you need to track one or two variables.
  • Example: Counter, form input handling.
import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>Count: {count}</button>
  );
}
Enter fullscreen mode Exit fullscreen mode

Here, useState is used for creating a simple counter. On button click, the setCount function updates the state.

Use useReducer when:

  • The state is complex, and you need to handle multiple state updates together.
  • Example: Todo app, form validation.
import { useReducer, useState } from "react";

function todoReducer(state, action) {
  switch (action.type) {
    case "add":
      return [...state, { text: action.payload, completed: false }];
    case "toggle":
      return state.map((todo, index) =>
        index === action.index ? { ...todo, completed: !todo.completed } : todo
      );
    case "remove":
      return state.filter((_, index) => index !== action.index);
    default:
      return state;
  }
}

function TodoApp() {
  const [todos, dispatch] = useReducer(todoReducer, []);
  const [input, setInput] = useState("");

  return (
    <div>
      <h2>Todo App using useReducer</h2>
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <button onClick={() => dispatch({ type: "add", payload: input })}>Add Todo</button>
      <ul>
        {todos.map((todo, index) => (
          <li key={index} style={{ textDecoration: todo.completed ? "line-through" : "none" }}>
            {todo.text}
            <button onClick={() => dispatch({ type: "toggle", index })}>Toggle</button>
            <button onClick={() => dispatch({ type: "remove", index })}>Remove</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TodoApp;
Enter fullscreen mode Exit fullscreen mode

Here, useReducer is used for complex state management. The dispatch function triggers the actions that modify the state.


useEffect vs. useLayoutEffect: React Hooks for Side Effects and Layout

Use useEffect when:

  • You need to perform side effects after rendering the component.
  • Example: API calls, event listeners, timers.
import { useEffect, useState } from "react";

function FetchData() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/todos/1")
      .then((response) => response.json())
      .then((json) => setData(json));
  }, []);

  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}
Enter fullscreen mode Exit fullscreen mode

Here, useEffect is used to fetch data from an API. This API sends the request after the component renders.

Use useLayoutEffect when:

  • You need to modify something right after the DOM update.
  • Example: Animation adjustments, measuring DOM elements.
import { useLayoutEffect, useRef } from "react";

function Box() {
  const boxRef = useRef(null);

  useLayoutEffect(() => {
    console.log("Box width:", boxRef.current.offsetWidth);
  });

  return <div ref={boxRef} style={{ width: "100px", height: "100px", background: "red" }} />;
}
Enter fullscreen mode Exit fullscreen mode

Here, useLayoutEffect is used to measure the width of the element right after the DOM update.


Comparing React Hooks for Performance: useMemo, useCallback, and useRef

Use useRef when:

  • You need to reference a DOM element directly.
  • You need to track the state update without re-rendering.
import { useRef } from "react";

function InputFocus() {
  const inputRef = useRef(null);

  return (
    <>
      <input ref={inputRef} type="text" />
      <button onClick={() => inputRef.current.focus()}>Focus</button>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Here, useRef is used to directly refer to the input field so that on button click, the focus can be set.

Use useMemo when:

  • You need to optimize expensive calculations.
  • You need to avoid unnecessary re-renders.
import { useState, useMemo } from "react";

function ExpensiveComponent({ numbers }) {
  function sum(numbers) {
    console.log("Calculating sum...");
    return numbers.reduce((acc, num) => acc + num, 0);
  }

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

  const total = useMemo(() => sum(numbers), [numbers]); // Recalculates only when `numbers` change

  return (
    <div>
      <p>Sum: {total}</p>
      <button onClick={() => setCount(count + 1)}>Re-render: {count}</button>
    </div>
  );
}

export default function App() {
  return <ExpensiveComponent numbers={[1, 2, 3, 4, 5]} />;
}
Enter fullscreen mode Exit fullscreen mode

Here, useMemo is used to cache expensive calculations so that this doesn’t recalculate on each render.

Use useCallback when:

  • You need to memoize a function so that it doesn’t re-create unnecessarily.
  • You need to prevent the child component from unnecessary re-renders.
import { useState, useCallback } from "react";

function ChildComponent({ handleClick }) {
  console.log("Child re-rendered!"); // This will only re-render when function changes

  return <button onClick={handleClick}>Click Me</button>;
}

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

  const handleClick = useCallback(() => {
    console.log("Button clicked!");
  }, []); // Function reference will not change

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <ChildComponent handleClick={handleClick} />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Here, useCallback is used to memoize the function so that the Button component doesn’t re-render unnecessarily.


useContext

Use useContext when:

  • You need to share the global state without props drilling.
  • Example: Theme toggle, user authentication.
import { createContext, useContext, useState } from "react";

const ThemeContext = createContext();

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("light");
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

function ThemedButton() {
  const { theme, setTheme } = useContext(ThemeContext);
  return (
    <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>Toggle Theme</button>
  );
}
Enter fullscreen mode Exit fullscreen mode

Here, useContext is used to share a global state (theme) so that multiple components can access the state without prop drilling.


Comparison Table

Hook When to use?
useState For simple state
useReducer For complex state logic
useEffect For side effects and async tasks
useLayoutEffect For UI modifications after DOM updates
useRef For DOM reference and mutable values
useMemo For optimizing expensive calculations
useCallback For optimizing function re-creation
useContext For global state management

Using the right React hook is important for code maintainability and performance optimization.


🎯Wrapping Up

That’s all for today!

For paid collaboration connect with me at : connect@shefali.dev

I hope this post helps you.

If you found this post helpful, here’s how you can support my work:
Buy me a coffee – Every little contribution keeps me motivated!
📩 Subscribe to my newsletter – Get the latest tech tips, tools & resources.
𝕏 Follow me on X (Twitter) – I share daily web development tips & insights.

Keep coding & happy learning!

Top comments (0)