React Mastery / React Hooks

Conditionally Run Effects

👉 What Does “Conditionally Run useEffect” Mean?

  • By default, useEffect runs after every render.

  • Conditionally running useEffect means:

    • The effect runs only when certain conditions are met

    • Or only when specific values change

This is mainly controlled using the dependency array and conditions inside the effect.


👉 Why Do We Need Conditional Effects?

  • Prevent unnecessary API calls

  • Avoid infinite loops

  • Improve performance

  • Run effects only when meaningful data changes

  • Handle user-driven actions (login, toggle, button click)


Method 1: Using Dependency Array (Most Common)

✅ Run effect only when a value changes

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

✔️ Runs only when count changes

❌ Does NOT run for other state updates

✅ Run effect only once (on mount)

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

✔️ Equivalent to componentDidMount


Method 2: Conditional Logic Inside useEffect

Sometimes you want the effect to run, but the logic inside it should execute only when a condition is true.

Example: Run only if count > 0

useEffect(() => {
  if (count > 0) {
    console.log("Count is greater than 0");
  }
}, [count]);

✔️ Effect runs on every count change

✔️ Logic executes conditionally

Example: API Call Only When User Logs In

useEffect(() => {
  if (!isLoggedIn) return;

  fetch("/api/profile")
    .then(res => res.json())
    .then(data => console.log(data));
}, [isLoggedIn]);

🧠 Explanation:

  • Effect listens to isLoggedIn

  • API runs only when user becomes logged in

  • Prevents unnecessary API calls


Method 3: Using Multiple useEffects (Best Practice)

Instead of complex conditions, split effects.

❌ Bad (hard to read)

useEffect(() => {
  if (type === "title") {
    document.title = text;
  }

  if (type === "timer") {
    startTimer();
  }
}, [type, text]);

✅ Good (separate concerns)

useEffect(() => {
  document.title = text;
}, [text]);

useEffect(() => {
  if (type !== "timer") return;
  startTimer();
}, [type]);

✔️ Easier to maintain

✔️ Clear responsibility per effect


Method 4: Conditional Cleanup

Cleanup also runs conditionally based on dependencies.

useEffect(() => {
  if (!isActive) return;

  const timer = setInterval(() => {
    console.log("Active...");
  }, 1000);

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

✔️ Timer starts only when isActive is true

✔️ Cleanup runs when isActive becomes false


❌ Common Mistakes

Missing dependency

useEffect(() => {
  console.log(count);
}, []); // ❌ count missing

➡️ Leads to stale values

Using condition instead of dependency

useEffect(() => {
  if (count === 5) {
    doSomething();
  }
}, []); // ❌ never runs when count changes

👉 Golden Rules for Conditional useEffect

✅ Always include all used variables in dependency array

✅ Use conditions inside effect, not outside

✅ Split effects for unrelated logic

✅ Prefer dependency-based control over manual flags


🔁 Class Component Mapping (Quick)

Requirement

Class Component

useEffect

Run once

componentDidMount

useEffect(..., [])

On update

componentDidUpdate

useEffect(..., [dep])

Conditional update

prevState check

if inside effect

Cleanup

componentWillUnmount

return () => {}