useEffect Hook Demo

What is useEffect?

useEffect is a React Hook that lets you perform side effects in functional components. It serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount combined in React class components.

Basic Syntax:

useEffect(() => {
  // Side effect code here
  console.log('Effect runs');
  
  // Optional cleanup function
  return () => {
    console.log('Cleanup runs');
  };
}, [dependencies]); // Optional dependency array

// Common patterns:
useEffect(() => {}); // Runs on every render
useEffect(() => {}, []); // Runs only once (mount)
useEffect(() => {}, [count]); // Runs when count changes

Basic useEffect Example

0

Current page title: Loading...

Check the browser tab title - it updates automatically when count changes!

This example shows useEffect with dependency array: useEffect(() => {}, [count])

Multiple Dependencies Example

Current Title: useEffect Demo

This effect depends on both 'count' and 'pageTitle' variables

This example shows useEffect with multiple dependencies: useEffect(() => {}, [count, pageTitle])

Auto-fetch on Mount Example

🔄 Loading data automatically...

This data was fetched automatically when the component mounted using: useEffect(() => {}, [])

Manual Data Fetching Example

This example shows async data fetching with loading and error states

Timer & Cleanup Example

⏱️ 0s

Timer Status: 🔴 Stopped

✅ This example shows useEffect with cleanup functions to prevent memory leaks

Event Listener Example

Window Size: Loading...

Try resizing your browser window to see this update in real-time!

✅ This example shows useEffect for event listeners with proper cleanup

Local Storage Example

Saved Text: (empty)

This text is automatically saved to localStorage and will persist across page refreshes!

✅ This example shows useEffect for data persistence with localStorage

⚠️ Common Gotchas & Best Practices

1. Missing Dependencies

Always include all variables from component scope that are used inside useEffect in the dependency array.

❌ Wrong:

useEffect(() => {
  console.log(count);
}, []); // Missing 'count' in dependencies

✅ Correct:

useEffect(() => {
  console.log(count);
}, [count]); // Include 'count' in dependencies

2. Memory Leaks

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

❌ Wrong:

useEffect(() => {
  const interval = setInterval(() => {
    console.log('tick');
  }, 1000);
  // No cleanup!
}, []);

✅ Correct:

useEffect(() => {
  const interval = setInterval(() => {
    console.log('tick');
  }, 1000);
  
  return () => clearInterval(interval);
}, []);

3. Infinite Loops

Be careful with object/array dependencies and missing dependency arrays.

❌ Wrong:

useEffect(() => {
  setUser({ name: 'John' });
}); // No dependency array = runs on every render

✅ Correct:

useEffect(() => {
  setUser({ name: 'John' });
}, []); // Empty array = runs once on mount

💡 Best Practices

  • Use multiple useEffect hooks for different concerns (separation of concerns)
  • Always provide a dependency array (even if empty)
  • Use the ESLint plugin react-hooks/exhaustive-deps to catch missing dependencies
  • Consider using useCallback/useMemo for object/function dependencies
  • Clean up subscriptions, timers, and event listeners in the return function
  • Handle async operations carefully (components might unmount before async operations complete)