Welcome back to the React Mastery Series!

In the previous article, we explored Forms in React and learned how controlled components help React manage user input.

Today, we will dive into one of the most important and widely used React Hooks:

useEffect Hook

useEffect is a fundamental Hook used in almost every real-world React application.

It helps us perform side effects such as:

  • Fetching data from APIs
  • Updating browser titles
  • Subscribing to events
  • Setting timers
  • Connecting to WebSockets
  • Cleaning up resources

Understanding useEffect is essential for building production-ready React applications.


What Are Side Effects?

Before understanding useEffect, we need to understand what a side effect is.

A side effect is any operation that happens outside the normal component rendering process.

Examples:

API Calls

Component Render
        |
        ↓
Call Backend API
        |
        ↓
Receive Data
        |
        ↓
Update State

Enter fullscreen mode Exit fullscreen mode


Browser Interaction

Examples:

  • Changing document title
  • Accessing local storage
  • Manipulating browser APIs

Subscriptions

Examples:

  • WebSocket connections
  • Event listeners
  • Timers

Why Do We Need useEffect?

React components should ideally be pure functions.

Example:

function UserProfile() {
  return <h1>User Profile</h1>;
}

Enter fullscreen mode Exit fullscreen mode

The component receives data and returns UI.

However, real applications need external interactions.

Example:

Render Component
       |
       ↓
Fetch User Data
       |
       ↓
Update UI

Enter fullscreen mode Exit fullscreen mode

React provides useEffect to handle these operations safely.


Basic Syntax of useEffect

useEffect(() => {
  // Side effect logic
}, []);

Enter fullscreen mode Exit fullscreen mode

The Hook accepts two parameters:

useEffect(
    function,
    dependency array
)

Enter fullscreen mode Exit fullscreen mode


First Parameter: Effect Function

This contains the code that should execute.

Example:

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

Enter fullscreen mode Exit fullscreen mode


Second Parameter: Dependency Array

The dependency array controls when the effect runs.

Example:

useEffect(() => {
  console.log("Runs once");
}, []);

Enter fullscreen mode Exit fullscreen mode

The empty array means:

Run this effect only after the initial render.


Understanding useEffect Execution

Consider:

function App() {
  useEffect(() => {
    console.log("Effect executed");
  }, []);

  return <h1>Hello React</h1>;
}

Enter fullscreen mode Exit fullscreen mode

Execution flow:

Component Created
        |
        ↓
Initial Render
        |
        ↓
DOM Updated
        |
        ↓
useEffect Executes

Enter fullscreen mode Exit fullscreen mode

Important:

useEffect runs after the component renders.


useEffect Without Dependency Array

Example:

useEffect(()=>{
  console.log("Runs every render");
});

Enter fullscreen mode Exit fullscreen mode

Execution:

Initial Render
       ↓
Effect Runs

State Update
       ↓
Render
       ↓
Effect Runs Again

Enter fullscreen mode Exit fullscreen mode

This happens after every render.

Use carefully.


useEffect With Empty Dependency Array

Example:

useEffect(()=>{
  console.log("Runs once");
},[]);

Enter fullscreen mode Exit fullscreen mode

Execution:

Component Mount
        |
        ↓
Effect Executes Once

Enter fullscreen mode Exit fullscreen mode

Common use cases:

  • Initial API calls
  • Loading configuration
  • Setting up subscriptions

useEffect With Dependencies

Example:

useEffect(()=>{
  console.log("User changed");
},[userId]);

Enter fullscreen mode Exit fullscreen mode

Now the effect runs when:

userId changes

Enter fullscreen mode Exit fullscreen mode

Example:

setUserId(10);

Enter fullscreen mode Exit fullscreen mode

Flow:

State Update
      |
      ↓
Component Re-render
      |
      ↓
Dependency Changed
      |
      ↓
useEffect Executes

Enter fullscreen mode Exit fullscreen mode


Real-World Example: Fetching API Data

A common React pattern:

import { useEffect, useState } from "react";

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

  useEffect(() => {
    fetch("https://api.example.com/users")
      .then((response) => response.json())
      .then((data) => {
        setUsers(data);
      });
  }, []);

  return (
    <div>
      {users.map((user) => (
        <h3 key={user.id}>{user.name}</h3>
      ))}
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

Flow:

Component Loads
        |
        ↓
useEffect Runs
        |
        ↓
API Request
        |
        ↓
Receive Response
        |
        ↓
Update State
        |
        ↓
Render User List

Enter fullscreen mode Exit fullscreen mode


Cleanup Function in useEffect

Some effects need cleanup.

Examples:

  • Removing event listeners
  • Clearing timers
  • Closing WebSocket connections

Example:

useEffect(() => {
    const timer =
        setInterval(() => {
            console.log("Running");
        }, 1000);

    return () => {
        clearInterval(timer);
    };
}, []);

Enter fullscreen mode Exit fullscreen mode

The function returned from useEffect is called Cleanup Function


Component Lifecycle Using useEffect

In class components:

componentDidMount()

componentDidUpdate()

componentWillUnmount()

Enter fullscreen mode Exit fullscreen mode

In functional components:

useEffect handles all lifecycle behavior.


Mounting

Equivalent to:

componentDidMount()

Enter fullscreen mode Exit fullscreen mode

Example:

useEffect(()=>{
   loadData();
},[]);

Enter fullscreen mode Exit fullscreen mode

Runs once when component appears.


Updating

Equivalent to:

componentDidUpdate()

Enter fullscreen mode Exit fullscreen mode

Example:

useEffect(()=>{
   searchProducts();
},[searchText]);

Enter fullscreen mode Exit fullscreen mode

Runs whenever searchText changes.


Unmounting

Equivalent to:

componentWillUnmount()

Enter fullscreen mode Exit fullscreen mode

Example:

useEffect(() => {
    return () => {
        disconnect();
    };
}, []);

Enter fullscreen mode Exit fullscreen mode

Runs when component is removed.


Real-World Example: WebSocket Connection

Imagine a live banking notification system.

Component loads:

Open Dashboard
       |
       ↓
Create WebSocket Connection
       |
       ↓
Receive Transaction Alerts

Enter fullscreen mode Exit fullscreen mode

When user leaves:

Navigate Away
       |
       ↓
Close WebSocket

Enter fullscreen mode Exit fullscreen mode

Implementation:

useEffect(() => {
    const socket =
        new WebSocket(
            "wss://bank.com/alerts"
        );
    return () => {
        socket.close();
    };
}, []);

Enter fullscreen mode Exit fullscreen mode


Dependency Array Mistakes

Mistake 1: Missing Dependencies

Example:

useEffect(()=>{
   fetchUser(userId);
},[]);

Enter fullscreen mode Exit fullscreen mode

Problem:

userId is used but not included.

Correct:

useEffect(()=>{
   fetchUser(userId);
},[userId]);

Enter fullscreen mode Exit fullscreen mode


Mistake 2: Infinite Loops

Example:

useEffect(()=>{
  setCount(count+1);
},[count]);

Enter fullscreen mode Exit fullscreen mode

Flow:

count changes
      |
      ↓
Effect runs
      |
      ↓
setCount()
      |
      ↓
count changes again
      |
      ↓
Infinite Loop

Enter fullscreen mode Exit fullscreen mode


useEffect vs Event Handlers

A common confusion:

Should something happen inside:

  • useEffect?
  • Button click handler?

Example:

User clicks save button:

<button onClick={saveData}> Save </button>

Enter fullscreen mode Exit fullscreen mode

This belongs in an event handler.


Automatic behavior:

Component Loaded
       |
       ↓
Fetch Data

Enter fullscreen mode Exit fullscreen mode

This belongs in:

useEffect()

Enter fullscreen mode Exit fullscreen mode


useEffect Best Practices

Keep Effects Focused

Avoid:

useEffect(()=>{
  fetchData();
  updateTitle();
  connectSocket();
},[]);

Enter fullscreen mode Exit fullscreen mode

Better:

useEffect(()=>{
  fetchData();
},[]);


useEffect(()=>{
  connectSocket();
},[]);

Enter fullscreen mode Exit fullscreen mode


Avoid Unnecessary Effects

Do not use effects for simple calculations.

Avoid:

useEffect(()=>{
  setFullName( firstName + lastName);
},[firstName,lastName]);

Enter fullscreen mode Exit fullscreen mode

Instead:

const fullName = firstName + lastName;

Enter fullscreen mode Exit fullscreen mode


Always Cleanup Resources

Cleanup:

  • Timers
  • Subscriptions
  • Event listeners
  • Connections

Enterprise Example: Banking Dashboard

Consider a retail banking application.

When the dashboard opens:

User Opens Dashboard
          |
          ↓
useEffect Executes
          |
          ↓
Fetch Account Summary API
          |
          ↓
Fetch Transactions API
          |
          ↓
Update State
          |
          ↓
Render Dashboard

Enter fullscreen mode Exit fullscreen mode

When leaving:

User Leaves Page
          |
          ↓
Cleanup Runs
          |
          ↓
Close Connections

Enter fullscreen mode Exit fullscreen mode

This pattern is used in production React applications.


Key Takeaways

Today, we learned:

useEffect handles side effects in React.
✅ Effects run after rendering.
✅ Dependency arrays control execution timing.
✅ Empty dependency arrays run effects once.
✅ Cleanup functions prevent memory leaks.
✅ API calls, subscriptions, and timers commonly use useEffect.


Coming Next 🚀

In Day 14, we will explore:

React Hooks Deep Dive – useRef and useMemo

We will learn:

  • What useRef is
  • Accessing DOM elements
  • Persisting values without re-rendering
  • useMemo for performance optimization
  • Expensive calculations
  • Real-world optimization examples

These Hooks are essential for writing high-performance React applications.

Happy Coding! 🚀