5 Types of React Hooks Explained – With Code Examples

Curious to know how to use React hooks? As a React beginner, I had many issues trying to understand hooks and their purpose.

But, as I kept on using them, I understood their purpose and some very powerful hooks in React that optimized the code for production.

In this blog, I will explain hooks in React, how to use hooks in React, and what prebuilt hooks are available in React.

how to use react hooks

Let’s dive into the blog to master React Hooks.

React Hooks

React Hooks are a new addition to React that allows you to use state and other React features without writing a class component.

JavaScript functions known as “Hooks” allow you to “hook into” React state and lifecycle features from function components.

React Hooks are methods that allow you to make use of state and other React capabilities without writing a class component.

They “hook into” React state and lifecycle features from function components and simplify state management.

Common React Hooks include: useState(), useReducer(), useEffect(), useLayoutEffect(), useCallback() and useMemo().

How To Use React Hooks?

Hooks are JavaScript functions, but they impose two additional rules:

  • Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions.
  • Only call Hooks from React function components. Don’t call Hooks from regular JavaScript functions. (There is just one other valid place to call Hooks — your own custom Hooks.)

Next, you will see some of the mostly used built-in hooks in react with example.

State Hooks

State lets a component “remember” information like user input. For example, a form component can use state to store the input value, while an image gallery component can use state to store the selected image index.

To add state to a component, use one of these Hooks:

  • useState declares a state variable that you can update directly.
  • useReducer declares a state variable with the update logic inside a reducer function.

Example of useState

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Example of useReducer

import { useReducer } from 'react';

export function ReducerExample() {
  const [state, dispatch] = useReducer(reducer, 0);

  function reducer(state, action) {
    switch (action.type) {
      case 'increment':
        return state + 1;
      case 'decrement':
        return state - 1;
      default:
        return state;
    }
  }

  return (
    <div className="example">
      <p>Count: {state}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>⬆️</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>⬇️</button>
    </div>
  );
}

Context Hooks

Context lets a component receive information from distant parents without passing it as props. For example, your app’s top-level component can pass the current UI theme to all components below, no matter how deep.

Example of useContext

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

export function ContextExample() {
  const [color, setColor] = useState('light');

  function changeTheme() {
    setColor((color) => {
      if (color === 'light') return 'dark';
      else return 'light';
    });
  }

  return (
    <Producer state={color}>
      <Consumer>
        <button onClick={() => changeTheme()}>
          {color === 'light' ? 'Dark' : 'Light'}
        </button>
      </Consumer>
    </Producer>
  );
}

const ThemeContext = createContext();
function Producer({ state, children }) {
  return (
    <ThemeContext.Provider value={state}>{children}</ThemeContext.Provider>
  );
}

function Consumer({ children }) {
  const theme = useContext(ThemeContext);

  return <div className={`example theme-${theme}`}>{children}</div>;
}

Ref Hooks

Refs let a component hold some information that isn’t used for rendering, like a DOM node or a timeout ID. Unlike with state, updating a ref does not re-render your component.

Refs are an “escape hatch” from the React paradigm. They are useful when you need to work with non-React systems, such as the built-in browser APIs.

  • useRef declares a ref. You can hold any value in it, but most often it’s used to hold a DOM node.
  • useImperativeHandle lets you customize the ref exposed by your component. This is rarely used.

Example of useRef

import { useState, useRef } from "react";

export default function Player() {
  const playerNameRef = useRef();

  const [playerName, setPlayerName] = useState();

  function handleSetName() {
    setPlayerName(playerNameRef.current.value);
    playerNameRef.current.value = "";
  }

  return (
    <section id="player">
      <h2>Welcome {playerName || "unknown entity"}</h2>
      <p>
        <input ref={playerNameRef} type="text" />
        <button onClick={handleSetName}>Set Name</button>
      </p>
    </section>
  );
}

Example of useImperativeHandle

import { forwardRef, useImperativeHandle, useRef } from "react";
import { createPortal } from "react-dom";

const ResultsModal = forwardRef(
  ({ targetTime, remainingTime, onReset }, ref) => {
    const dialog = useRef();

    const userLost = remainingTime <= 0;
    const formattedRemainingTime = (remainingTime / 1000).toFixed(2);
    const score = ((1 - remainingTime / (targetTime * 1000)) * 100).toFixed();

    useImperativeHandle(ref, () => ({
      open() {
        dialog.current.showModal();
      },
    }));

    return createPortal(
      <dialog ref={dialog} className="result-modal" onClose={onReset}>
        {userLost && <h2>You lost</h2>}
        {!userLost && <h2>Your score {score}</h2>}
        <p>
          Your target time was <strong>{targetTime} seconds.</strong>
        </p>
        <p>
          You stopped the timer with{" "}
          <strong>{formattedRemainingTime} seconds left.</strong>
        </p>
        <form method="dialog" onSubmit={onReset}>
          <button>Close</button>
        </form>
      </dialog>,
      document.getElementById("modal")
    );
  }
);

export default ResultsModal;

Effect Hooks

Effects let a component connect to and synchronize with external systems. This includes dealing with network, browser DOM, animations, widgets written using a different UI library, and other non-React code.

  • useEffect connects a component to an external system.

Want to learn more about handling side effects in React using useEffect? Then, read about how to handle side effects from The Startup Coder.

Example of useEffect

import { useRef, useEffect } from "react";
import { createPortal } from "react-dom";

function Modal({ open, onClose, children }) {
  const dialog = useRef();

  useEffect(() => {
    if (open) {
      dialog.current.showModal();
    } else {
      dialog.current.close();
    }
  }, [open]);

  return createPortal(
    <dialog className="modal" ref={dialog} onClose={onClose}>
      {open ? children : null}
    </dialog>,
    document.getElementById("modal")
  );
}

export default Modal;

Performance Hooks

A common way to optimize re-rendering performance is to skip unnecessary work. For example, you can tell React to reuse a cached calculation or to skip a re-render if the data has not changed since the previous render.

To skip calculations and unnecessary re-rendering, use one of these Hooks:

  • useMemo lets you cache the result of an expensive calculation.
  • useCallback lets you cache a function definition before passing it down to an optimized component.

Example of useMemo

import { useState, useMemo } from "react";
import ReactDOM from "react-dom/client";

const App = () => {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);
  const calculation = useMemo(() => expensiveCalculation(count), [count]);

  const increment = () => {
    setCount((c) => c + 1);
  };
  const addTodo = () => {
    setTodos((t) => [...t, "New Todo"]);
  };

  return (
    <div>
      <div>
        <h2>My Todos</h2>
        {todos.map((todo, index) => {
          return <p key={index}>{todo}</p>;
        })}
        <button onClick={addTodo}>Add Todo</button>
      </div>
      <hr />
      <div>
        Count: {count}
        <button onClick={increment}>+</button>
        <h2>Expensive Calculation</h2>
        {calculation}
      </div>
    </div>
  );
};

const expensiveCalculation = (num) => {
  console.log("Calculating...");
  for (let i = 0; i < 1000000000; i++) {
    num += 1;
  }
  return num;
};

Example of useCallback

function ProductPage({ productId, referrer, theme }) {
  // Tell React to cache your function between re-renders...
  const handleSubmit = useCallback((orderDetails) => {
    post('/product/' + productId + '/buy', {
      referrer,
      orderDetails,
    });
  }, [productId, referrer]); // ...so as long as these dependencies don't change...

  return (
    <div className={theme}>
      {/* ...ShippingForm will receive the same props and can skip re-rendering */}
      <ShippingForm onSubmit={handleSubmit} />
    </div>
  );
}

Conclusion

In summary, you have learned about React hooks, how they are used, some built-in React hooks along examples.

I would recommend you practice React hooks by yourself as they could be tricky for beginners (sometimes even for intermediates) to understand at first.

With this, I hope you will use some of the hooks mentioned in this blog in your projects or even in your work.

Thanks, see you soon!!

Hi, I’m Arup—a full-stack engineer at Enegma and a blogger sharing my learnings. I write about coding tips, lessons from my mistakes, and how I’m improving in both work and life. If you’re into coding, personal growth, or finding ways to level up in life, my blog is for you. Read my blogs for relatable stories and actionable steps to inspire your own journey. Let’s grow and succeed together! 🚀

Leave a Reply

Your email address will not be published. Required fields are marked *