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

export default function App() {
  const [name, setName] = useState('');
  
  useEffect(() => {
    if (name !== '') {
      document.title = `Welcome, ${name}!`;
    } else {
      document.title = 'React App';
    }
  }, [name]);

  const handleInputChange = (event) => {
    setName(event.target.value);
  };

  return (
    <div>
      <h1>Welcome, {name || 'Stranger'}!</h1>
      <input type="text" value={name} onChange={handleInputChange} placeholder="Enter your name" /> 
    </div>
  );
}

The effect hook is used to interact with external sources, outside of React. Runs on component mount, re-render due to state/prop changes, or unmounted from DOM.

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

export default function MyComponent({ userId }) {
  const [data, setData] = useState(null);

  useEffect(() => {
    let isMounted = true;

    const fetchData = async () => {
      try {
        const response = await fetch(`https://api.example.com/data/${userId}`); 
        const jsonData = await response.json();

        if (isMounted) {
          setData(jsonData);
        }
      } catch (error) {
        console.error('Error fetching data:', error);
      }
    };

    fetchData();

    return () => {
      isMounted = false;
    };
  }, [userId]);

  return (
    <div>
      {data ? (
        <ul>
          {data.map(item => (
            <li key={item.id}>{item.name}</li>
          ))}
        </ul>
      ) : (
        <p>Loading data...</p>
      )}
    </div>
  );
};

The Effect hook is also used to work with the Fetch API. Important to know when to call our useEffect function when dealing with APIs.

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

export default function CounterComponent() {
  const [count, setCount] = useState(0);
  const [isPaused, setIsPaused] = useState(false);

  useEffect(() => {
    const interval = setInterval(() => {
      if (!isPaused) {
        setCount(prevCount => prevCount + 1);
      }
    }, 1000);

    return () => {
      clearInterval(interval);
    };
  }, [isPaused]);

  const handlePauseResume = () => {
    setIsPaused(prevPaused => !prevPaused);
  };

  return (
    <div>
      <h1>Counter</h1>
      <p>Count: {count}</p>
      <button onClick={handlePauseResume}>
        {isPaused ? 'Resume' : 'Pause'}
      </button>
    </div>
  );
}

Dependency arrays control when effects are called. Second argument to the useEffect call, an empty array means it should only call once. Variables in the array, if one or more changes, executes useEffect function.

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

const TimerComponent = () => {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    // Timer
    const timer = setInterval(() => {
      setSeconds(prevSeconds => prevSeconds + 1);
    }, 1000);

    // Cleanup function
    return () => {
      clearInterval(timer);
    };
  }, []); // Empty dependency array ensures the effect runs only once

  return (
    <div>
      <h1>Timer: {seconds} seconds</h1>
    </div>
  );
};

export default TimerComponent;

Interacting with the BOM, outside of React, might need useEffect to cleanup unwanted "side effects". Using localStorage, BOM methods, or anything else might need to use useEffect for cleanups, for desired outcomes.

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

export default function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log('Effect is running');
    
    const timer = setInterval(() => {
      setCount((prevCount) => prevCount + 1);
    }, 1000);

    // Clean up the timer when the component unmounts or when count reaches 5 
    return () => {
      console.log('Cleanup function is running');
      clearInterval(timer);
    };
  }, []);

  return (
    <div>
      <h1>Count: {count}</h1>
    </div>
  );
}

Some effects require cleanup. Removing unwanted effects once done with them. Returning a cleanup function is used to cleanup effects. Runs before the Effects runs again, and before unmounting.

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

const DomExample = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // Update document title when count changes
    document.title = `Count: ${count}`;

    // Add event listener to document body
    const handleKeyDown = event => {
      if (event.key === 'Enter') {
        setCount(prevCount => prevCount + 1);
      }
    };
    document.body.addEventListener('keydown', handleKeyDown);

    // Cleanup function
    return () => {
      // Reset document title
      document.title = 'React App';

      // Remove event listener from document body
      document.body.removeEventListener('keydown', handleKeyDown);
    };
  }, [count]);

  return (
    <div>
      <p>Press Enter key to increase count: {count}</p>
    </div>
  );
};

export default DomExample;

The DOM, also outside of React, might need some cleanup after done with wanted executions. Adding events, styling, or changing content as well.