Next Hooks Master
Read This on Github
useEffect Tutorial
Explain
๐ A Beginner's Guide to useEffect

Welcome to the world of React Hooks! Today, we'll dive into one of the most popular hooks: useEffect. Don't worry, we'll make it fun and easy to understand. So, let's get started! ๐
Change the image size by using the click-and-scroll function.
๐ What is useEffect
useEffect is a React Hook that allows you to perform side effects in your functional components. Side effects are actions that happen outside of your component, like fetching data, updating the DOM, or subscribing to events. With useEffect, you can manage these side effects without writing a class or function. ๐
๐งช How useEffect works
useEffect is like a Swiss Army knife ๐จ๐ญ๐ช for side effects in your functional components. It combines the functionality of componentDidMount, componentDidUpdate, and componentWillUnmount from class components into one simple hook.
Here's how it works:
- You call
useEffectwith a function that contains your side effect. - React runs your side effect function after rendering the component.
- If you provide a cleanup function, React will call it when the component is unmounted or when the dependencies change.
No need to write a class or function! ๐คฏ
โก Different use cases
Let's explore some common use cases for useEffect:
- Fetching data: You can use
useEffectto fetch data from an API and update your component's state when the data is received. ๐ฆ - Updating the document title: Want to change the title of your webpage based on the component's state?
useEffectto the rescue! ๐ฆธโโ๏ธ - Setting up event listeners: Need to listen for events like window resizing or keyboard input?
useEffectcan help you set up and clean up event listeners. ๐ง - Persisting state: Want to save your component's state to local storage or a database?
useEffectcan handle that too! ๐พ - Timers and intervals: If you need to set up a timer or interval in your component,
useEffectis the perfect tool for the job. You can start the timer when the component mounts and clear it when the component unmounts. โณ
๐ Examples of useEffect use cases ๐
Example 1: Fetching data
Strucutre
FetchData
โโโ button.tsx
โโโ location.tsx
โโโ weather.tsxbutton.tsx
import React, { useState, useEffect } from "react";
import fetchWeatherData from "./weather"; // Import the function to fetch weather data
interface WeatherProps {
location: string;
}
const WeatherButtons: React.FC<WeatherProps> = ({ location }) => {
const [weatherData, setWeatherData] = useState<any>(null); // Create state to hold weather data and initialize it to null
const [requestType, setRequestType] = useState<string>(""); // Create state to hold the type of request to make and initialize it to an empty string
useEffect(() => {
if (requestType) { // If a request type has been selected
fetchWeatherData(location, requestType).then((data: any) => // Call the function to fetch weather data
setWeatherData(data) // Set the weather data to the response from the API
);
}
}, [requestType, location]); // Run the effect when either request type or location changes
return (
<div className="text-2xl">
<button
className="weather-current-weather-button"
onClick={() => setRequestType("current")} // When the button is clicked, set the request type to "current"
>
Current Weather
</button>
{weatherData && ( // If weather data exists
<div className="weather-json-bg">
<pre className="weather-button-pre-wrap">
{JSON.stringify(weatherData, null, 2)} // Display the weather data as JSON
</pre>
</div>
)}
</div>
);
};
export default WeatherButtons;
This component renders a button that fetches weather data from the API when clicked. It has the following features:
- It imports the
useStateanduseEffecthooks from React, and thefetchWeatherDatafunction fromweather.tsx. - It receives the
locationprop from its parent component, which specifies the city for which weather data should be fetched. - It defines two state variables using the
useStatehook:weatherData, which stores the fetched weather data, andrequestType, which determines what type of weather data to fetch (e.g., current weather, 5-day forecast). - It uses the
useEffecthook to fetch weather data from the API whenrequestTypechanges (i.e., when the button is clicked), and update theweatherDatastate variable with the fetched data. - It renders a button with an
onClickevent that sets therequestTypestate variable to "current" (i.e., fetch current weather data). - If
weatherDatais not null, it renders apretag that displays the fetched data in JSON format.
location.tsx
import React, { createContext, useState } from "react";
export const LocationContext = createContext<any>(null); // Create a context object to hold location data
export const LocationProvider: React.FC = ({ children }) => { // Create a provider component for the context
const [location, setLocation] = useState<string>("New York"); // Create state to hold the current location and initialize it to "New York"
const changeLocation = (newLocation: string) => {
setLocation(newLocation); // Function to update the location
};
return (
<LocationContext.Provider value={{ location, changeLocation }}>
{children}
</LocationContext.Provider>
);
};
This component creates a context that stores the current location for which weather data should be fetched. It has the following features:
- It imports the
createContextanduseStatehooks from React. - It creates a
LocationContextusing thecreateContexthook, which is used to pass thelocationstate variable andchangeLocationfunction to child components. - It defines a
LocationProvidercomponent using theuseStatehook, which sets the initiallocationstate variable to "New York". - It defines a
changeLocationfunction that updates thelocationstate variable with a new location. - It renders the
LocationContext.Providercomponent with thelocationstate variable andchangeLocationfunction as its value, and its child components as its children.weather.tsx
const fetchWeatherData = async (
location: string,
requestType: string
): Promise<any> => {
const apiKey = process.env.NEXT_PUBLIC_WEATHER ?? ""; // Get the API key from the environment variables
const apiUrl = `https://api.openweathermap.org/data/2.5/weather?q=${location}&appid=${apiKey}`; // Construct the API URL using the location and API key
const response = await fetch(apiUrl); // Make a request to the API
const data = await response.json(); // Parse the response as JSON
return data; // Return the data
};
export default fetchWeatherData;
This component defines a function that fetches weather data from the OpenWeatherMap API using the provided location and requestType parameters. It has the following features:
- It defines an
asyncfunction calledfetchWeatherDatathat takes inlocationandrequestTypeparameters. - It gets the API key from an environment variable called
NEXT_PUBLIC_WEATHER. - It constructs the API URL using the
locationandapiKeyvariables, and usesfetchto make a GET request to the API. - It uses the
jsonmethod of the response object to convert the response to a JavaScript object. - It returns the fetched data as a
Promise.
How to use
import WeatherButtons from "../components/react/useEffect/FetchData/button";
import { LocationProvider } from "../components/react/useEffect/FetchData/location";
<LocationProvider>
<WeatherButtons
location="London"
units="metric"
theme="dark"
/>
</LocationProvider>To use these components, you can import WeatherButtons and LocationProvider into your own React component and wrap WeatherButtons inside LocationProvider. You can then pass in the desired location (and optionally, units and theme) props to WeatherButtons. When the button is clicked, the weather data for the specified location will be fetched and displayed in JSON format.
Example 2 - UserFetchData
UserFetch
โโโ Data.tsx
โโโ UserFetch.tsx
Data.tsx
import React, { useEffect, useState } from "react";
// Define the shape of the data object that will be returned by the hook
type Data<T> = {
status: "loading" | "success" | "error";
data?: T;
error?: Error;
};
// Custom hook that fetches data from an API endpoint and returns the data object
export function useFetch<T>(url: string): Data<T> {
// Create a state variable called 'data' and initialize it with { status: "loading" }
const [data, setData] = useState<Data<T>>({ status: "loading" });
// useEffect hook that runs when the URL changes
useEffect(() => {
// Define an asynchronous function called 'fetchData'
const fetchData = async () => {
try {
// Fetch data from the API endpoint
const response = await fetch(url);
const result = await response.json();
// Update the 'data' state variable with the fetched data
setData({ status: "success", data: result });
} catch (error) {
// Update the 'data' state variable with the error object
setData({ status: "error", error: error as Error });
}
};
// Call the 'fetchData' function to fetch data from the API endpoint
fetchData();
}, [url]); // Only run the effect when the url changes
// Return the 'data' object
return data;
}- The
Datatype defines the shape of the data object that will be returned by theuseFetchhook. It contains three properties:status,data, anderror. - The
useFetchfunction takes a URL as its parameter and returns thedataobject that was defined earlier. - Within the
useFetchfunction,useStateis used to create a state variabledataand its initial state is set to{ status: "loading" }. useEffectis used to fetch the data from the API endpoint. It runs only when the URL changes because[url]is passed as its second argument.- Inside the
useEffectfunction,fetchDatais an asynchronous function that usestryandcatchblocks to fetch the data from the API endpoint. If the fetch is successful, thesetDatafunction is called with{ status: "success", data: result }. If there is an error, thesetDatafunction is called with{ status: "error", error: error as Error }. - Finally,
useFetchreturns thedataobject.
UserFetch.tsx
import React, { useState } from "react";
import { useFetch } from "./Data";
function UsersFetch() {
// Create a state variable called 'url' and initialize it with the API endpoint URL
const [url, setUrl] = useState("https://jsonplaceholder.typicode.com/users");
// Call the 'useFetch' hook with the 'url' state variable
const data = useFetch<Array<{ id: number; name: string }>>(url);
// Render a button that changes the 'url' state variable when clicked
return (
<div>
<button
className="user-fetch-button"
onClick={() => setUrl(url + "?_limit=5")}
>
Fetch only 5 users
</button>
{/* If the 'status' property of the 'data' object is 'loading', render a loading message */}
{data.status === "loading" && <p>Loading...</p>}
{/* If the 'status' property of the 'data' object is 'success', render a list of users */}
{data.status === "success" && (
<ul className="user-fetch-data-bg">
{data.data?.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)}
{/* If the 'status' property of the 'data' object is 'error', render an error message */}
{data.status === "error" && <p>Error: {data.error?.message}</p>}
</div>
);
}
export default UsersFetch;- The
UsersFetchfunction is a React component that uses theuseFetchhook to fetch data from an API endpoint and render it. - The component uses
useStateto create a state variableurlwith an initial value of"https://jsonplaceholder.typicode.com/users". - The
datavariable is assigned the result of calling theuseFetchhook withurl. - A button is rendered that calls
setUrlwith a new URL when clicked. - The component renders different content depending on the
statusproperty of thedataobject. - If
statusis"loading", the component renders a loading message. - If
statusis"success", the component renders a list of users with their names. - If
statusis"error", the component renders an error message with the error object's message.
Example 3 - Widget
Widget
โโโ ColorWidget.tsx
โโโ Widget.tsxWidget.tsx
// This function creates a new widget element with the specified background color and adds it to the provided container element.
export function createWidget(color: string, container: HTMLElement) {
// Create a new div element to serve as the widget.
const widget = document.createElement("div");
// Set the widget's background color.
widget.style.background = color;
// Set the widget's width and height.
widget.style.width = "100px";
widget.style.height = "100px";
// Set the widget's border radius.
widget.style.borderRadius = "25%";
// Set the widget's margin.
widget.style.margin = "10px";
// Set the widget's border style and color.
widget.style.border = "2px solid pink";
// Create a new custom event to be dispatched periodically by the widget.
const statusChangeEvent = new CustomEvent("statusChange", {
detail: { status: "active" },
});
// Set an interval to dispatch the statusChangeEvent every 1000 milliseconds (1 second).
setInterval(() => {
widget.dispatchEvent(statusChangeEvent);
}, 1000);
// Add the widget to the container element.
container.appendChild(widget);
// Return an object with functions to add and remove event listeners, as well as to destroy the widget.
return {
addEventListener: widget.addEventListener.bind(widget),
removeEventListener: widget.removeEventListener.bind(widget),
destroy: () => container.removeChild(widget),
};
}
- Line 1: Define a function called
createWidgetthat takes two argumentscolor(string) andcontainer(HTMLElement). - Line 2-9: Create a new
divelement with the providedcolor, set its size, shape, margin, and border. - Line 11-15: Create a new custom event called
statusChangeEventwith adetailproperty containing{ status: "active" }. - Line 17-20: Dispatch the
statusChangeEventevery second. - Line 22: Append the
widgetto thecontainer. - Line 24-29: Return an object that has three properties:
addEventListener,removeEventListener, anddestroy.
ColorWidget.tsx
import React, { useEffect, useRef, useState } from "react";
import { createWidget } from "./Widget";
interface ColorWidgetProps {
initialColor: string;
}
const ColorWidget: React.FC<ColorWidgetProps> = ({ initialColor }) => {
// useRef hook to create a reference to the container div element
const containerRef = useRef<HTMLDivElement>(null);
// useState hook to create a state variable for the color of the widget
const [color, setColor] = useState(initialColor);
// useEffect hook to run side-effects when the component mounts or the color state changes
useEffect(() => {
// Get the current value of the container reference
const container = containerRef.current;
// If the container exists, create a widget and add event listeners to it
if (container) {
// Create the widget with the given color and container
const widget = createWidget(color, container);
// Define a function to handle the "statusChange" event of the widget
const handleStatusChange = (event: CustomEvent<{ status: string }>) => {
console.log("The status is:", event.detail.status);
};
// Add an event listener to the widget to listen for "statusChange" events
(widget as any).addEventListener("statusChange", handleStatusChange);
// Return a cleanup function to remove the widget and event listeners when the component unmounts or the color changes
return () => {
widget.destroy();
(widget as any).removeEventListener("statusChange", handleStatusChange);
};
}
}, [color]);
// Define a function to update the color state variable with a random hex color
const changeColor = () => {
setColor(
`#${Math.floor(Math.random() * 0x1000000)
.toString(16)
.padStart(6, "0")}`
);
};
// Render the ColorWidget component with a container div, a button to change the color, and the color widget itself
return (
<div className="color-widget">
<div className="widget-container" ref={containerRef}></div>
<button className="widget-button" onClick={changeColor}>
Change Color
</button>
</div>
);
};
export default ColorWidget;
- Line 1-8: Import necessary dependencies and define an interface for
ColorWidgetProps. - Line 10-18: Define a functional component called
ColorWidgetthat takesinitialColoras a prop and returns some JSX. - Line 19: Create a reference using
useRefto store a reference to adivelement. - Line 21-23: Define a state called
colorusinguseStateand initialize it withinitialColor. - Line 25-47: Use
useEffectto create a widget usingcreateWidget, add an event listener to it, and clean up the widget and event listener when thecolorchanges or the component is unmounted. - Line 33-39: Define a function called
changeColorthat generates a random hexadecimal color and sets it as the newcolor. - Line 42-46: Return some JSX that contains a
divwith arefto the container reference, a button with anonClickevent handler that callschangeColor, and some CSS classes for styling.
Example 4 - Conditional Effect
ConditionalEffect.tsx
import React, { useState, useEffect } from "react";
export const ConditionalEffect: React.FC = () => {
// state variables for count and message
const [count, setCount] = useState(0);
const [message, setMessage] = useState("");
// useEffect hook that runs whenever count changes
useEffect(() => {
// check if count is even or odd
if (count % 2 === 0) {
// set message to "Even" if count is even
setMessage("Even");
} else {
// set message to "Odd" if count is odd
setMessage("Odd");
}
}, [count]);
// render the component with a button that increments count on click
// also display the current message and count value
return (
<div>
<button
className="conditional-effect-button"
onClick={() => setCount(count + 1)}
>
Conditional Effect
</button>
<p className="conditional-effect-text">{message}</p>
<p className="conditional-effect-text">Count: {count}</p>
</div>
);
};
import React, { useState, useEffect } from "react";: imports React and the useState and useEffect hooks from thereactlibrary.const [count, setCount] = useState(0);: declares a state variablecountusing the useState hook with an initial value of 0 and a functionsetCountthat allows us to update thecountvariable.const [message, setMessage] = useState("");: declares a state variablemessageusing the useState hook with an initial value of an empty string and a functionsetMessagethat allows us to update themessagevariable.useEffect(() => {...}, [count]);: defines an effect that runs whenever thecountstate variable changes. Ifcountis even,messageis set to "Even", otherwise it is set to "Odd".<button className="conditional-effect-button" onClick={() => setCount(count + 1)}>Conditional Effect</button>: renders a button with a click handler that updates thecountstate variable when clicked.<p className="conditional-effect-text">{message}</p>: renders the value ofmessage.<p className="conditional-effect-text">Count: {count}</p>: renders the value ofcount.
Example 5 - Timer Effect
Timer.tsx
import React, { useState, useEffect } from "react";
export const Timer: React.FC = () => {
// Set the initial state of seconds to 0 using useState hook
const [seconds, setSeconds] = useState(0);
useEffect(() => {
// Set an interval to increment seconds state by 1 every 1000ms using setInterval
const interval = setInterval(() => {
setSeconds((seconds) => seconds + 1);
}, 1000);
// Clear the interval using clearInterval in the cleanup function
return () => {
clearInterval(interval);
};
}, []); // Effect only runs once (empty dependency array)
return (
<div>
<p className="timer-text">
You have been on this page for {seconds} seconds.
</p>
</div>
);
};import React, { useState, useEffect } from "react";: Import the necessary React components.const [seconds, setSeconds] = useState(0);: Declare a state variablesecondsand its corresponding updater functionsetSeconds, initialized to0.useEffect(() => {...}, []);: Use theuseEffecthook to execute a side effect after the initial render and run cleanup before unmount. The dependency array is empty, so the effect will only run once after the initial render.const interval = setInterval(() => {...}, 1000);: Set an interval to increment thesecondsstate by 1 every second.setSeconds((seconds) => seconds + 1);: Update thesecondsstate with the updater function to increment its value by 1.return () => {...};: Return a cleanup function to clear the interval when the component is unmounted.<p className="timer-text">You have been on this page for {seconds} seconds.</p>: Render a paragraph element that displays thesecondsstate variable.
Example 6 - Update Title
UpdateTitle.tsx
import React, { useEffect, useState } from "react";
export function UpdateTItle() {
const [count, setCount] = useState(0); // create a state variable 'count' and its update function 'setCount' with an initial value of 0
useEffect(() => {
// This is a side effect that runs when the component mounts, and whenever 'count' changes
// It updates the document title with the current count
document.title = `You clicked ${count} times`;
}, [count]); // Only run the effect when 'count' changes
return (
<div>
<p className="update-title-text">You clicked {count} times</p>
<button
className="update-title-button"
onClick={() => setCount(count + 1)}
>
Click me
</button>
</div>
);
}
- The code defines a React functional component called
UpdateTitle. - The component initializes a state variable
countwith an initial value of 0, and its corresponding update functionsetCount. - The
useEffecthook is used to create a side effect that runs when the component mounts and whenevercountchanges. - Inside the effect, the document title is updated with the current value of
countinterpolated into a string. - The
useEffecthook takes an array of dependencies as its second argument. When any of the dependencies change, the effect will run again. In this case, the effect only depends oncount, so it will only run whencountchanges. - The component returns a div containing a paragraph element that displays the current value of
count, and a button that updatescountwhen clicked.
That's it! Now you have a solid understanding of useEffect and how it can help you manage state in your React functional components. Happy coding! ๐