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:
Rendering: The component is rendered, and the
useEffect
hook is called.Effect Function: The effect function is executed after the component has been rendered.
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.
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