React JS - useEffect

Everything about useEffect hook in detailed.

ยท

5 min read

React JS - useEffect

UseEffect

The useEffect hook in React is a powerful tool for managing side effects in functional components. It allows you to run some code after rendering a component, and also to handle cleanup after the component is unmounted.

The basic syntax of useEffect is as follows:

1 import { useEffect } from 'react';
2
3 function MyComponent() {
4  useEffect(() => {
5    // code to run after rendering
6  }, [dependencies]);
7  return <div>Hello World!</div>;
8}

In this example, the useEffect hook takes two arguments:

  • A function to run after rendering (the "effect" function)

  • An array of dependencies (optional)

How it Works

Here's a step-by-step breakdown of how useEffect works:

  1. Rendering: The component is rendered, and the useEffect hook is called.

  2. Effect Function: The effect function is executed after the component has been rendered.

  3. Dependencies: If the dependencies array is provided, React will check if any of the dependencies have changed since the last render. If they have, the effect function will be re-run.

  4. Cleanup: If the component is unmounted, the effect function will be called with a cleanup function as an argument. This allows you to perform any necessary cleanup.

Example Use Cases

1. Fetching Data

1 import { useState, useEffect } from 'react';
2
3 function MyComponent() {
4  const [data, setData] = useState([]);
5  useEffect(() => {
6    fetch('https://jsonplaceholder.typicode.com/posts')
7      .then(response => response.json())
8      .then(data => setData(data));
9  }, []);
10  return <div>Data: {data}</div>;
11}

In this example, we use useEffect to fetch data from an API after the component has been rendered.

2. Handling Events

1 import { useState, useEffect } from 'react';
2
3 function MyComponent() {
4  const [count, setCount] = useState(0);
5  useEffect(() => {
6    document.addEventListener('click', () => setCount(count + 1));
7    return () => document.removeEventListener('click', () => 
             setCount(count + 1));
8  }, [count]);
9  return <div>Count: {count}</div>;
10}

In this example, we use useEffect to handle a click event and update the component state.

3. Animations

1 import { useState, useEffect } from 'react';
2
3 function MyComponent() {
4  const [animate, setAnimate] = useState(false);
5  useEffect(() => {
6    const animation = setTimeout(() => setAnimate(true), 1000);
7    return () => clearTimeout(animation);
8  }, []);
9  return <div className={animate ? 'animate' : ''}>Hello World!</div>;
10 }

In this example, we use useEffect to animate a component after a delay.

Best Practices

  • Always provide a dependencies array to ensure the effect function is re-run when necessary.

  • Use the cleanup function to perform any necessary cleanup when the component is unmounted.

  • Avoid using useEffect for complex logic or computations. Instead, use a separate function or a library like Redux.

Fetching Data After the Component is Rendered

// Calling an API with useEffect using Promise
import { useEffect } from "react";

const url = "https://jsonplaceholder.typicode.com/posts";
export function FetchData() {
  useEffect(() => {
    fetch(url)
      .then((response) => response.json())
      .then((data) => {
        console.log(data);
      });
  }, []);
  return <div></div>;
}
//calling an API with useEffect using async await
import { useEffect } from "react";

const url = "https://jsonplaceholder.typicode.com/posts";
export function FetchData() {
      async function fetchedData() {
            const response = await fetch(url)
            const data = await response.json()
            console.log(data);
      }
  useEffect(() => {
      fetchedData();
  },[]);

  return <div></div>;
}

Show Data Using UseEffect

import { useEffect, useState } from "react";
import { User } from "./User";

const URL = "https://jsonplaceholder.typicode.com/users";

export function FetchData() {
  const [users, setUsers] = useState([]);

  //for loading Effect => Throttling
  const[isLoading, setIsLoading] = useState(true);

  //For error checking
  const [error, setError] = useState(false)

  async function fetchedData() {
    const response = await fetch(URL);
    if (response.status >=200 && response.status<=299) {
      const data = await response.json();
      setUsers(data);
    }
    else{
      setError(true)
    }
    setIsLoading(false)
  }
  useEffect(() => {
    fetchedData();
  }, []);

  if(isLoading){
      return <h1>Loading ....</h1>
  }

  if (error) {
    return <h1>Something went Wrong</h1>
  }
  return (
    <div>
      {users.map((user) => (
         <User key={user.id} {...user}/>
      ))}
    </div>
  );
}

Cleanup for Fetching Data

//App.jsx
import { useState } from "react";
// import { CleanupFunctionDemo } from "./CleanupFunctionDemo";
// import { MouseMoveEvent } from "./MouseMoveEvent";
import {FetchData} from "./FetchData"

//Strict Mode -> for useEffect ->

//useEffect run
//cleanup function
//useEffect run again
function App() {
  const [showComponent, setShowComponent] = useState(true);
  return (
    <>
      {/* <ExampleUseEffect /> */}
      {/* <FetchData/> */}

      <label htmlFor="showComponent">show Component</label>
      <input
        type="checkbox"
        name="showComponent"
        id="showComponent"
        checked={showComponent}
        onChange={() => setShowComponent(!showComponent)}
      />
      {showComponent && <FetchData />}
    </>
  );
}
export default App;
//fetchData.jsx
import { useEffect, useState } from "react";
import { User } from "./User";

const URL = "https://jsonplaceholder.typicode.com/users";

export function FetchData() {
  const [users, setUsers] = useState([]);

  //for loading Effect => Throttling
  const[isLoading, setIsLoading] = useState(true);

  //For error checking
  const [error, setError] = useState(false)

  useEffect(() =>{
    //for Aborting on fetching the data
    const controller = new AbortController();
    const signal = controller.signal;

    async function fetchedData() {
      //we can pass signal onject 
    const response = await fetch(URL, { signal:signal });
    if (response.status >=200 && response.status<=299) {
      const data = await response.json();
      setUsers(data);
    }
    else{
      setError(true)
    }
    setIsLoading(false)
  }

    fetchedData();
    //this return is for cleanup function for useEffect
    return ()=>{
      console.log('aborting request....');
      controller.abort()

    }
  }, []);

  if(isLoading){
      return <h1>Loading ....</h1>
  }

  if (error) {
    return <h1>Something went Wrong</h1>
  }
  return (
    <div>
      {users.map((user) => (
         <User key={user.id} {...user}/>
      ))}
    </div>
  );
}

Cleanup Function Example

import { useEffect, useState } from "react";

//cleanup function

//1: before component unmount

//2: when there is some value in dependency array     

//when value of counter changes
//component rendered
//cleanup function rendered
//useEffect rendered

export function CleanupFunctionDemo() {
  console.log("component rendered");
  const [counter, setcounter] = useState(0);
  useEffect(() => {
      console.log("useEffect rendered");
      return function(){
            console.log('cleanup function rendered');
      }

  }, [counter]);

  return (
    <>
      <div>
        <h3>Counter : {counter}</h3>
        <br />
        <button onClick={() => setcounter((prevCounter) => prevCounter + 1)}>
          Increase
        </button>
      </div>
    </>
  );
}

Mouse Move Event

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

export function MouseMoveEvent() {
  const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });

  useEffect(() => {
    const handleMouseMove = (e) => {
      console.log({ x: e.clientX, y: e.clientY });
      setMousePosition({ x: e.clientX, y: e.clientY });
    };
    document.addEventListener("mousemove", handleMouseMove);
    return () => {
      console.log("cleanup function");
      document.removeEventListener("mousemove", handleMouseMove);
    };
  }, []);
  return (
    <div>
      <p>x: {mousePosition.x}</p>
      <p>y: {mousePosition.y}</p>
    </div>
  );
}

GitHub Code : UseEffect

ย