React useEffect Patterns for Reliable Side Effects

🧠 useEffect Cheat Sheet (Beginner → Confident)

1️⃣ What is useEffect? (Plain English)

useEffect lets you run side effects in a React component.

👉 Side effects = things that are not UI rendering.

  • Fetching data
  • Calling APIs
  • Using localStorage
  • Timers (setTimeout, setInterval)
  • Event listeners
  • Updating the document title

Rule of thumb:
If it touches the outside world, it belongs in useEffect.


2️⃣ Basic Syntax (Memorize This)

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

📌 Two parts:

  1. Effect function → what to run
  2. Dependency array → when to run

3️⃣ The 3 Most Important Patterns (MUST KNOW)

✅ 1. Run once (on component mount)

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

🧠 Think:

“Run this once when the component appears.”

📌 Common use cases:

  • API calls
  • Initial setup
  • Fetching data

✅ 2. Run when something changes

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

🧠 Think:

“Whenever count changes, run this.”

📌 Use cases:

  • Re-fetching data
  • Syncing state
  • Updating the document title

❌ 3. Run on every render (rare & dangerous)

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

⚠️ Avoid unless you really know why — this runs after every render.


4️⃣ Real Examples (Very Important)

🔹 Change document title

useEffect(() => {
  document.title = `Count: ${count}`;
}, [count]);

✔ Runs only when count changes.


🔹 Fetching data from API

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

✔ Fetches once when the component mounts.


🔹 Using localStorage

useEffect(() => {
  localStorage.setItem("name", name);
}, [name]);

✔ Syncs state with browser storage.


5️⃣ Cleanup Function (VERY IMPORTANT)

Some effects must be cleaned up or bugs and leaks can happen.

Syntax

useEffect(() => {
  return () => {
    // cleanup code
  };
}, []);

🔹 Example: Event listener

useEffect(() => {
  const handleResize = () => {
    console.log(window.innerWidth);
  };
  window.addEventListener("resize", handleResize);
  return () => {
    window.removeEventListener("resize", handleResize);
  };
}, []);

🧠 Think:

“Clean up before the component unmounts.”


🔹 Example: setInterval

useEffect(() => {
  const id = setInterval(() => {
    console.log("Tick");
  }, 1000);
  return () => clearInterval(id);
}, []);

6️⃣ Dependency Array — How to Think

Rule

👉 Everything you use inside useEffect that comes from outside the effect should go in the dependency array.

Example

useEffect(() => {
  console.log(name, age);
}, [name, age]);

❌ Wrong

useEffect(() => {
  console.log(name);
}, []); // ❌ name used but not listed

This causes stale values.


7️⃣ Infinite Loop Problem (Common Beginner Mistake)

❌ Wrong

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

👉 The effect updates countcount triggers the effect again → 💥 infinite loop.


✅ Fix using functional update

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

8️⃣ Multiple useEffects (Best Practice)

Prefer multiple small, focused effects over one large effect.

// One big effect (less ideal)
useEffect(() => {
  fetchData();
  updateTitle();
  addListener();
}, []);

// Better: multiple focused effects
useEffect(fetchData, []);
useEffect(updateTitle, [count]);
useEffect(addListener, []);

🧠 Cleaner and easier to debug.


9️⃣ When NOT to Use useEffect

❌ Don’t use useEffect for things that belong in render or derived values:

  • Updating state directly from props
  • Simple calculations
  • Rendering logic

👉 Do this instead:

const total = price * quantity;

If it can be done during render — do not use useEffect.


🔟 Mental Model (Remember This Forever)

Render = describe UI
useEffect = sync with outside world


🔥 Common Mistakes Checklist

  • ❌ Forgetting the dependency array
  • ❌ Updating state without cleanup
  • ❌ Using useEffect for simple calculations
  • ❌ Causing infinite loops
  • ❌ Ignoring cleanup functions

🧪 Tiny Practice Snippet

useEffect(() => {
  console.log("Hello React");
}, []);

Ask yourself:

  • When does it run? ✅ once
  • Why? ✅ empty dependency array