React Mastery / React Hooks

useEffect Hook

❓ Introduction: What is useEffect?

  • useEffect is a React Hook that lets you perform side effects in function components.

  • A side effect is anything that:

    • Interacts with the outside world

    • Doesn’t directly return UI

Common side effects:

  • Fetching data from an API

  • Updating the browser title

  • Adding event listeners

  • Setting timers (setTimeout, setInterval)

  • Subscribing / unsubscribing to services

👉 Before Hooks, these were handled using lifecycle methods in class components.


🔴 Side Effects in Class Components

In class components, side effects are spread across lifecycle methods:

Lifecycle Method

Purpose

componentDidMount()

Runs after first render

componentDidUpdate()

Runs after updates

componentWillUnmount()

Cleanup before removal

❌ Problems:

  • Repetition – same logic in multiple lifecycle methods

  • Fragmentation – setup in one place, cleanup in another

  • Hard to maintain – unrelated code grouped together


❓ Why useEffect?

✔️ useEffect replaces all three lifecycle methods

✔️ Groups related logic in one place

✔️ Makes components cleaner & easier to understand

What is useEffect & When Does It Run?

  • useEffect runs after the component renders

  • By default:

    • Runs after first render

    • Runs after every update

💡 React says:

“Don’t think in lifecycle phases — think in effects.”


✏️ Syntax of useEffect

useEffect(() => {
  // Side effect logic

  return () => {
    // Cleanup logic (optional)
  };
}, [dependencies]);

Explanation:

  • Effect function → Runs after render

  • Cleanup function → Runs before unmount OR before re-running effect

  • Dependency array → Controls when effect runs

💊 Dependency Array – How It Works

Dependency Array

When effect runs

❌ Not provided

After every render

[]

Only once (on mount)

[value]

When value changes


Simple Example: Update Document Title

🎯 Goal:

Update browser tab title when count changes.

✅ Function Component with useEffect

🧠 What’s happening?

  • Runs on first render

  • Runs again only when count changes

  • Replaces:

    • componentDidMount

    • componentDidUpdate


👉 Example: Run Effect Only Once (componentDidMount)

🎯 Goal:

Log message only when component loads.

useEffect(() => {
  console.log("Component mounted");
}, []);

✔️ Runs only once

✔️ Similar to componentDidMount


🧹 Cleanup Example (componentWillUnmount)

🎯 Goal:

Start a timer and clear it when component unmounts.

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

  return () => {
    clearInterval(timer);
    console.log("Cleanup done");
  };
}, []);

🧠 Explanation:

  • Timer starts when component mounts

  • Cleanup runs when component unmounts

  • Replaces componentWillUnmount


🧠 Multiple useEffects (Best Practice)

👉 Use separate effects for unrelated logic

useEffect(() => {
  document.title = "My App";
}, []);

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

✔️ Cleaner

✔️ Easier to debug

✔️ Better separation of concerns


🔴 Common Mistakes to Avoid

❌ Missing dependencies

❌ Putting everything in one useEffect

❌ Forgetting cleanup for timers/listeners

❌ Creating infinite loops by updating state inside effect without proper dependencies


🚀 When Should You Use useEffect?

Use useEffect when you need to:

✔️ Fetch data after render

✔️ Update DOM manually

✔️ Add/remove event listeners

✔️ Start/stop timers

✔️ Subscribe/unsubscribe to services

❌ Don’t use it for pure UI logic (that belongs in render)


✅ Summary

  • useEffect handles side effects in function components

  • Replaces all major class lifecycle methods

  • Dependency array controls execution

  • Cleanup keeps your app memory-safe

  • Multiple effects = cleaner code