How to Implement React Hooks in React

React Hooks allow you to use state and other React features in functional components without writing class components. This article provides a direct, step-by-step guide on how to implement the most common React Hooks—specifically useState and useEffect—while outlining the essential rules you must follow to use them correctly.

The Rules of Hooks

Before implementing hooks, you must adhere to two core rules enforced by React:

  1. Only call Hooks at the top level: Do not call Hooks inside loops, conditions, or nested functions. This ensures Hooks are called in the same order each time a component renders.
  2. Only call Hooks from React functions: Call them from React functional components or custom Hooks, not from regular JavaScript functions.

Implementing State with the useState Hook

The useState Hook allows you to add state to a functional component. It returns an array with two elements: the current state value and a function to update it.

Step 1: Import the Hook

Import useState from the react package at the top of your file.

import React, { useState } from 'react';

Step 2: Initialize the Hook

Call useState inside your functional component. Pass the initial state as an argument.

function Counter() {
  // Declare a state variable named "count" initialized to 0
  const [count, setCount] = useState(0);

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

Implementing Side Effects with the useEffect Hook

The useEffect Hook lets you perform side effects in functional components, such as data fetching, subscriptions, or manually changing the DOM. It serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in React classes.

Step 1: Import the Hook

Import useEffect alongside React.

import React, { useState, useEffect } from 'react';

Step 2: Implement the Hook

Pass a function to useEffect. This function contains the side-effect logic.

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

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

    // Cleanup function (runs when the component unmounts)
    return () => clearInterval(interval);
  }, []); // Empty dependency array means this runs once on mount

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

Understanding the Dependency Array

The second argument passed to useEffect is the dependency array, which controls when the effect runs: * No array: The effect runs after every single render. * Empty array []: The effect runs once after the initial render (like componentDidMount). * Array with values [prop, state]: The effect runs only when the specified values change.