From Confusion to Clarity: Understanding useEffect in React

Muhammad Hassan Saeed
4 min readMar 10, 2025

--

I have been using React for the past six months, but one concept always confused me — useEffect. No matter how many times I encountered it, I struggled to understand when and how to use it properly. However, this week, I decided to focus entirely on useEffect and finally cleared all my doubts. In this article, I will share everything I’ve learned to help others who might be facing the same confusion.

What is useEffect ?

useEffect is a built-in React Hook 🪝 that allows you to handle side effects in functional components. Side effects include

  • when component re-renders
  • when component mounts
  • The State of a value change

Fetching data

Updating the DOM

Setting up subscriptions

or Working with timers-intervals

things that go beyond rendering UI elements. Before React Hooks, side effects were handled using lifecycle methods in class components like componentDidMount, componentDidUpdate, and componentWillUnmount. However, useEffect simplifies this process for functional components.

For more info about Side effects visit https://refine.dev/blog/useeffect-cleanup/#what-are-side-effects

UseEffect using Patterns:

useEffect(() => {})       -    Runs every re-renders
useEffect(() => {},[]) - Runs only on mounts
useEffect(() => {}, [dep]) - Runs on mount + when value changes
  1. UseEffect without Dependency Array
import { useEffect, useState } from "react"

export const CounterFunc = () => {

const [count,setCount] = useState(0)

return (
<>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
</div>
</>
)
}

What we done here that we create basic CounterFunction and use add default css class to parent div for more interactive look.

useEffect( () =>  {
document.title = `Count is ${count}`
console.log("UseEffect renders")
})

2. UseEffect with Empty Dependency Array

Let use same code above and explore what empty array do to our current logic.

useEffect( () =>  {
document.title = `Count is ${count}`
console.log("UseEffect renders")
},[])

// Adding Console.log for more understanding
Renders Only once
Triggers only once

3. UseEffect with Dependency Array

Let’s add more code to understand dependency array.

 const [colour,setcolour] = useState("green")

function handlecolor(){
return setcolour(c => c === "green" ? "red" : "green")
}

<button onClick={handlecolor}>
Change Colour
</button>

<p style={{color: colour}}>Colour: {colour}</p>

Here is full code

import { useEffect, useState } from "react"
import '../../App.css'

const CounterFunc= () => {

const [count,setCount] = useState(0)
const [colour,setcolour] = useState("green")

useEffect( () => {
document.title = `Count is ${count} ${colour}`
console.log(`UseEffect renders ${colour} `)

})

function handlecolor(){
return setcolour(c => c === "green" ? "red" : "green")
}

return (
<>

<div className="card">
<p style={{color: colour}}>Colour: {colour}</p>
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<button onClick={handlecolor}>
Change Colour
</button>
</div>
</>
)
}

export default CounterFunc;

Let’s see What we have done yet.

Perfect ! Working as expected, As we go with wihout dep array it triggers useEffect on every Re-render.

useEffect( () =>  {
document.title = `Count is ${count} ${colour}`
console.log(`UseEffect renders ${colour} `)

},[count])
Now its only trigger when count state change

What if we add both color and count state to dependency array.

I think Now You Understand UseEffect better. So we need to keep moving 🚲.

Real-World Example:

  • Setting Width and Height of Screen
import React , {useState,useEffect} from 'react'

const Listnersideeffects = () => {
const [width,setwidth] = useState(window.innerWidth)
const [height,setheight] = useState(window.innerHeight)

const handleresize = () => {
setwidth(window.innerWidth)
setheight(window.innerHeight)
}


window.addEventListener("resize", handleresize)
console.log("Event listner added")



return (
<>
<p>Window width: {width}</p>
<p>Window Height: {height}</p>
</>
)
}

export default Listnersideeffects
Too much Console.logs

What if we use that logic in useEffect ?

  useEffect(() => {
window.addEventListener("resize", handleresize)
console.log("Event listner added")

},[])

Boom 🎆

Cleanup Logic — Return Function in UseEffect

useEffect cleanup is a function in the useEffect Hook that saves applications from unwanted behaviors by cleaning up effects.

return(() => {
window.removeEventListener("resize",handleresize)
console.log("Event listner Removed")
})

When to use UseEffect ?

  • Data Fetching
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/todos')
.then(res => res.json())
.then(data => setData(data));
}, []);
  • DOM Manipulations
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]);
  • Event listeners
useEffect(() => {
window.addEventListener("keydown", handleUserKeyPress);
}, [handleUserKeyPress]);;

That’s it from my side. Here is some references and useful assest:

Happy Learning 😃

--

--

Muhammad Hassan Saeed
Muhammad Hassan Saeed

Written by Muhammad Hassan Saeed

Full Stack Developer | Aws-Certified SAA

No responses yet