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 count β†’ count 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