0
0
ReactHow-ToBeginner · 4 min read

Common Mistakes with useEffect in React and How to Avoid Them

Common mistakes with useEffect include missing dependencies in the dependency array, causing effects to run too often or not at all, and creating infinite loops by updating state inside the effect without proper conditions. Always include all variables your effect uses in the dependency array and avoid side effects that cause continuous re-renders.
📐

Syntax

The useEffect hook runs side effects in React components. It takes two arguments: a function to run the effect, and an optional dependency array that controls when the effect runs.

  • Effect function: Code to run after render, like fetching data or updating the DOM.
  • Dependency array: List of variables that trigger the effect when they change. If empty, effect runs once after first render.
javascript
useEffect(() => {
  // effect code here
  return () => {
    // cleanup code here (optional)
  };
}, [dependencies]);
💻

Example

This example shows a counter that updates the document title using useEffect. The effect runs only when the counter changes because the counter is in the dependency array.

javascript
import React, { useState, useEffect } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

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

  return (
    <div>
      <p>Count is {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

export default Counter;
Output
A webpage showing "Count is 0" and a button labeled "Increment". Clicking the button increases the count and updates the browser tab title to "Count: X" where X is the current count.
⚠️

Common Pitfalls

1. Missing dependencies: Forgetting to list variables used inside the effect causes stale values or missed updates.

2. Infinite loops: Updating state inside useEffect without proper dependency control causes the effect to run endlessly.

3. Overusing effects: Running effects on every render by omitting the dependency array hurts performance.

4. Incorrect cleanup: Not cleaning up subscriptions or timers can cause memory leaks.

javascript
import React, { useState, useEffect } from 'react';

function WrongExample() {
  const [count, setCount] = useState(0);

  // Wrong: missing dependency array causes effect to run every render
  useEffect(() => {
    console.log('Effect runs every render');
  });

  // Wrong: updating state inside effect without proper condition causes infinite loop
  useEffect(() => {
    setCount(count + 1);
  }, [count]);

  return <p>Count: {count}</p>;
}

function FixedExample() {
  const [count, setCount] = useState(0);

  // Correct: effect runs only once
  useEffect(() => {
    console.log('Effect runs once');
  }, []);

  // Correct: update state with condition or different dependency
  useEffect(() => {
    if (count < 5) {
      setCount(count + 1);
    }
  }, [count]);

  return <p>Count: {count}</p>;
}
📊

Quick Reference

  • Always include all variables your effect uses in the dependency array.
  • Use an empty array [] to run effect only once after mount.
  • Clean up subscriptions or timers in the return function to avoid leaks.
  • Avoid updating state inside useEffect without conditions to prevent infinite loops.
  • Use React DevTools to check effect runs and dependencies.

Key Takeaways

Always list all variables used inside useEffect in its dependency array.
Avoid updating state inside useEffect without proper conditions to prevent infinite loops.
Use an empty dependency array to run effects only once after the component mounts.
Clean up side effects like timers or subscriptions in the effect's cleanup function.
Check your effects with React DevTools to ensure they run as expected.