In React, components re-render whenever state or props change. But sometimes, you need to run extra code after rendering. For example:

  1. Fetching data from an API
  2. Setting up a subscription or Event Emitter
  3. Updating the DOM manually
  4. Running code only once when a component loads

For these tasks, React provides the useEffect hook.

useEffect is a built-in lifecycle hook that lets you perform side effects in your component. A “side effect” means anything that happens outside the component rendering process, like network requests, timers, or manually changing the DOM.


import { useEffect } from "react";

useEffect(() => {   // setup function

  // Code to run after render

},[]);      // dependencies in array (optional)
        

useEffect Hook

useEffect hook is a built-in lifecycle hook in React that allows you to perform side effects in your functional components. It is called after the component renders and can be used for tasks such as data fetching, subscriptions, or manually changing the DOM.

useEffect hook takes two arguments: a function that contains the side effect code, and an optional array of dependencies. The effect function will run after the render is committed to the screen.

Here's a basic example of how to use the useEffect hook:


import { useEffect } from "react";

function Hello() {
  useEffect(() => {
    console.log("Component rendered!");
  });

  return <h2>Hello React</h2>
}

useEffect using click event

useEffect can be used on events like, click, change etc.


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

function ExampleComponent() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    // This code runs after every render
    document.title = `You clicked ${count} times`;
  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

In this example, the ExampleComponent uses the useEffect hook to update the document title every time the component renders. The effect function runs after every render because we did not provide a dependency array.


Using useEffect with Dependency Array

You can optimize the performance of your component by providing a dependency array as the second argument to the useEffect hook. The effect function will only run when one of the dependencies in the array changes.

Here's an example:


  import { useState, useEffect } from "react";

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

  useEffect(() => {
    console.log("Count changed:", count);
  }, [count]);

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

In this example, the effect function will only run when the count state changes. Changes to the name state will not trigger the effect, optimizing performance.


Cleaning up with useEffect

Sometimes, you need to clean up after your side effects to prevent memory leaks or unwanted behavior. You can do this by returning a cleanup function from the effect function.

Here's an example of using a cleanup function in useEffect:


import { useState, useEffect } from "react";
function Timer() {
  const [seconds, setSeconds] = useState(0);

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

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

  return <div>Seconds: {seconds}</div>
}

In this example, the Timer component sets up an interval to increment the seconds state every second. The cleanup function returned from the effect clears the interval when the component unmounts, preventing memory leaks.