useEffect Hook

0/2 in this phase0/36 across the roadmap

📖 Concept

useEffect allows you to perform side effects in functional components. A "side effect" is anything that happens outside the scope of the React render cycle (e.g., fetching data, manual DOM manipulation, timers).

The Signature: useEffect(() => { ... }, [dependencies]);

The Three Scenarios:

  1. No Dependency Array: Runs on every render. (Rarely used)
  2. Empty Dependency Array []: Runs only once after the initial mount.
  3. With Dependencies [prop, state]: Runs after the initial mount and whenever any dependency changes.

The Cleanup Function: If your effect creates something that needs to be cleaned up (like a timer or a subscription), you return a function from useEffect. React runs this cleanup function before the component unmounts and before re-running the effect.

💻 Code Example

codeTap to expand ⛶
1import React, { useState, useEffect } from 'react';
2
3function MouseTracker() {
4 const [position, setPosition] = useState({ x: 0, y: 0 });
5
6 useEffect(() => {
7 // 1. Setup the effect
8 const handleMove = (e) => {
9 setPosition({ x: e.clientX, y: e.clientY });
10 console.log('Mouse moved');
11 };
12
13 window.addEventListener('mousemove', handleMove);
14
15 // 2. Return the CLEANUP function
16 // This prevents memory leaks and multiple listeners
17 return () => {
18 window.removeEventListener('mousemove', handleMove);
19 console.log('Cleanup: Listener removed');
20 };
21 }, []); // 3. Empty array = run only on mount
22
23 return (
24 <div className="p-4 bg-gray-100 rounded">
25 <p>Move your mouse!</p>
26 <pre>X: {position.x}, Y: {position.y}</pre>
27 </div>
28 );
29}
30
31function SearchComponent() {
32 const [query, setQuery] = useState('');
33 const [results, setResults] = useState([]);
34
35 useEffect(() => {
36 // 4. Run effect when 'query' changes
37 if (!query) return;
38
39 const controller = new AbortController();
40
41 const fetchData = async () => {
42 try {
43 const res = await fetch(`https://api.example.com/search?q=${query}`, {
44 signal: controller.signal
45 });
46 const data = await res.json();
47 setResults(data);
48 } catch (err) {
49 if (err.name !== 'AbortError') console.error(err);
50 }
51 };
52
53 fetchData();
54
55 // 5. Abort fetch if query changes quickly (debounce-like)
56 return () => controller.abort();
57 }, [query]);
58
59 return (
60 <input
61 value={query}
62 onChange={(e) => setQuery(e.target.value)}
63 placeholder="Search..."
64 className="border p-2"
65 />
66 );
67}

🏋️ Practice Exercise

  1. Build a 'Clock' component that updates the time every second using setInterval. Don't forget the cleanup!
  2. Create a component that fetches a random user from an API when it mounts.
  3. Implement a 'Window Size' hook that tracks the browser's width and height.
  4. Try to trigger an infinite loop by updating a state variable that is also in the dependency array of the effect. Use the browser console to see it happen (and then fix it!).

⚠️ Common Mistakes

  • Forgetting the dependency array (causing the effect to run on every render).

  • Lying to React about dependencies (not including a variable you use inside the effect).

  • Performing side effects directly in the component body (instead of inside useEffect).

  • Not providing a cleanup function for subscriptions or timers.

💼 Interview Questions

🎤 Mock Interview

Practice a live interview for useEffect Hook