⚡ Lesson 5: useEffect & Side Effects

Learn how useEffect manages side effects, event listeners, timers, and API calls!

🎯 Current Effect Settings (Change these above!)

Timer Effects:

Auto-increment: ON

Speed: 1000ms

Initial Counter: 0

Event Tracking:

Window Size: ON

Mouse Position: ON

Keyboard: ON

API Effects:

Auto-fetch: ON

API Delay: 2000ms

Max Attempts: 3

⏱️ Timer Effects

0

Started at: 0 | Auto-increment: 1000ms

🖱️ Event Tracking

Window Size:0 × 0
Mouse Position:X: 0, Y: 0
Last Key:None

📡 API Effects & Data Fetching

API Status: idle

No fetch initiated

Fetch Settings:

Auto-fetch: ON

Delay: 2000ms

Attempts: 0/3

Success Rate: ~70%

📋 Effect Logs (Last 10 activities)

No effect logs yet...

🎯 What You're Experiencing

  • • Mount effects: Run once when component loads
  • • Dependency effects: Re-run when values change
  • • Cleanup: Remove timers and event listeners
  • • Event listeners: React to user interactions
  • • API calls: Fetch data with loading states

⚛️ useEffect Patterns

  • • No deps []: Runs once on mount
  • • With deps [value]: Runs when value changes
  • • No deps array: Runs on every render
  • • Cleanup function: Prevents memory leaks
  • • Conditional effects: Early returns to skip effects

📝 useEffect Code Patterns

1. Effect with Cleanup (Timer)

useEffect(() => {
  const timer = setInterval(() => {
    setCounter(prev => prev + 1);
  }, 1000);

  // Cleanup function - VERY IMPORTANT!
  return () => {
    clearInterval(timer);
  };
}, [1000]); // Re-run when speed changes

Always clean up timers, intervals, and subscriptions to prevent memory leaks.

2. Event Listener Pattern

useEffect(() => {
  if (!true) return; // Early return
  
  const handleMouseMove = (e) => {
    setMousePosition({ x: e.clientX, y: e.clientY });
  };

  window.addEventListener('mousemove', handleMouseMove);
  
  return () => {
    window.removeEventListener('mousemove', handleMouseMove);
  };
}, [true]);

Add event listeners in useEffect and remove them in cleanup function.

3. API Call with Dependencies

useEffect(() => {
  if (!shouldFetchData) return;
  
  const fetchData = async () => {
    setLoading(true);
    try {
      const response = await fetch('/api/data');
      const data = await response.json();
      setData(data);
    } catch (error) {
      setError(error.message);
    } finally {
      setLoading(false);
    }
  };
  
  fetchData();
}, [shouldFetchData, apiUrl]); // Re-fetch when these change

Use async functions inside useEffect for API calls. Handle loading and error states.

🚀 useEffect Challenge!

  1. 1. Set enableAutoIncrement = false - watch timer stop!
  2. 2. Change autoIncrementSpeed to 500ms - see faster counting
  3. 3. Disable trackMousePosition and move your mouse
  4. 4. Set apiDelay to 5000ms - watch the loading take longer
  5. 5. Try maxFetchAttempts = 1 to see fewer retries
  6. 6. Watch the effect logs to see when cleanup functions run!