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

Controlled vs Uncontrolled Components in React (Beginner Friendly)

When you start learning React, one of the first confusing topics you’ll face is the difference between Controlled and Uncontrolled Components. Don’t worry — by the end of this post, you’ll understand this clearly with simple examples.


🎯 What Does It Mean?

In simple words:

  • Controlled Component → React is in charge of the input’s value.
  • Uncontrolled Component → The browser (DOM) is in charge of the input’s value.

Think of it like this:

  • In Controlled Components, React acts like a teacher, checking every word you write in your notebook.
  • In Uncontrolled Components, React acts like a teacher who lets you write freely and only checks your notebook at the end.

📝 Controlled Components

In a controlled component, the form input is linked to React state. That means React always knows what’s inside the input, and it updates automatically when you type.

Example: Controlled Input

import React, { useState } from "react";

function ControlledForm() {
  const [name, setName] = useState(""); // React state

  const handleSubmit = (e) => {
    e.preventDefault();
    alert("Submitted Name: " + name);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={name} // value comes from React state
        onChange={(e) => setName(e.target.value)} // update state
        placeholder="Enter your name"
      />
      <button type="submit">Submit</button>
    </form>
  );
}

export default ControlledForm;

👉 Here:

  • The input value is always controlled by React.
  • When you type, React updates the state and then shows the updated value back in the input.
  • React is the single source of truth.

📝 Uncontrolled Components

In an uncontrolled component, the input manages its own value just like in plain HTML. You don’t use state, instead you use a ref to get the value when needed.

Example: Uncontrolled Input

import React, { useRef } from "react";

function UncontrolledForm() {
  const nameRef = useRef(); // reference to input

  const handleSubmit = (e) => {
    e.preventDefault();
    alert("Submitted Name: " + nameRef.current.value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        ref={nameRef} // React does not control this input
        placeholder="Enter your name"
      />
      <button type="submit">Submit</button>
    </form>
  );
}

export default UncontrolledForm;

👉 Here:

  • The browser keeps track of what you type.
  • React doesn’t know the input value until you read it with ref.
  • DOM is the source of truth.

🔑 Key Differences

FeatureControlledUncontrolled
Value managed byReact stateDOM (browser)
How to read valueFrom stateFrom ref.current.value
React controlHigh (can validate instantly)Low
Use caseValidation, dynamic forms, live feedbackSimple forms, quick data grab

🚀 When Should You Use Which?

  • ✅ Use Controlled Components when you need:
    • Form validation (e.g., check if email is valid while typing)
    • Live updates (e.g., show typed text somewhere else instantly)
    • Complex or large forms
  • ✅ Use Uncontrolled Components when you need:
    • Simple, one-time form submissions
    • Quick prototypes
    • Minimal React state management

🎓 Final Takeaway

  • Controlled → React is the boss. It decides what’s in the input.
  • Uncontrolled → Browser is the boss. React just asks for the value when needed.

👉 As a beginner, it’s usually best to start with Controlled Components because they give you more power and flexibility. But knowing Uncontrolled Components will help you understand how React works with the DOM.