React useEffect Explained Clearly (With Simple Examples)

If you are learning React, chances are useEffect confused you at least once.

Questions like:

  • Why does useEffect run twice?
  • When should I use it?
  • What is dependency array?
  • How is it different from lifecycle methods?

Don’t worry.
In this post, I’ll explain useEffect in the simplest way possible, using real-world analogies and clear examples.


What is useEffect in React?

👉 useEffect is used to perform side effects in React components.

Side effects include:

  • Fetching data from an API
  • Updating the DOM
  • Setting timers
  • Subscribing to events
  • Logging data

Simply put:

useEffect runs code when something changes in your component.


Basic Syntax of useEffect

useEffect(() => {
  // side effect code
}, []);

It has two parts:

  1. Effect function – what you want to do
  2. Dependency array – when you want to do it

Case 1: useEffect Without Dependency Array

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

What happens?

✅ Runs after every render

⚠️ Usually not recommended, can cause performance issues.


Case 2: useEffect With Empty Dependency Array []

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

What happens?

✅ Runs only once, after first render

Equivalent to:

componentDidMount()

👉 Most common use case: API calls


Example: Fetching Data

useEffect(() => {
  fetch("/api/users")
    .then(res => res.json())
    .then(data => setUsers(data));
}, []);

✔️ Fetches data only once
✔️ Avoids infinite loops


Case 3: useEffect With Dependencies

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

What happens?

✅ Runs only when count changes

👉 Useful for reacting to state or prop changes


Example: Search Input

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

✔️ Runs only when user types
✔️ Optimized & efficient


Cleanup Function in useEffect 🧹

Some effects need cleanup.

Example:

  • Timers
  • Event listeners
  • Subscriptions
useEffect(() => {
  const timer = setInterval(() => {
    console.log("Running...");
  }, 1000);

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

👉 Cleanup runs when:

  • Component unmounts
  • Dependencies change

Why Does useEffect Run Twice in React?

In React Strict Mode (development):

  • React runs effects twice
  • This helps detect bugs

🚨 It does NOT happen in production


Common Mistakes with useEffect ❌

❌ Missing dependency array

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

➡️ Causes infinite loop


❌ Incorrect dependencies

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

But fetchData uses props/state → bug!


When Should You Use useEffect?

Use useEffect when:
✅ You interact with outside world
✅ You perform side effects
❌ Not for simple calculations


Summary Table 📌

ScenarioDependency
Run once[]
Run on every renderNo array
Run on change[state/props]
Cleanup neededreturn () => {}

Final Thoughts

If you remember just one line, remember this:

useEffect syncs your React component with the outside world.

Mastering useEffect will:

  • Improve performance
  • Prevent bugs
  • Make you a better React developer

Leave a comment