Hands-on practice for this lecture. Work through the exercises and quizzes to reinforce what you've learned.
Exercise 1 of 3
Three useEffect snippets, three questions. Test how well you can predict when an effect runs based on its dependency array.
useEffect(() => {
document.title = 'Hello';
});How often does this effect run?
useEffect(() => {
fetchUser(userId);
}, []);When does this effect run? (userId is a prop)
useEffect(() => {
const id = setInterval(() => {
setCount(c => c + 1);
}, 1000);
return () => clearInterval(id);
}, []);The cleanup function runs…
0/3 answered
Exercise 2 of 3
Four useEffect snippets. Identify which ones cause infinite re-render loops and understand the pattern behind each one.
For each snippet, decide: does this cause an infinite loop?
Snippet 1
const [count, setCount] = useState(0);
useEffect(() => {
setCount(count + 1);
}, [count]);Snippet 2
const [data, setData] = useState(null);
useEffect(() => {
fetch('/api/user')
.then(r => r.json())
.then(setData);
}, []);Snippet 3
const [user, setUser] = useState({});
useEffect(() => {
setUser({ name: 'Durgesh' });
}, [user]);Snippet 4
const [theme, setTheme] = useState('dark');
useEffect(() => {
document.body.className = theme;
}, [theme]);0/4 answered
💡 Pattern: if your effect modifies a value that is in its own dep array, check whether the modification can cause a new render cycle. Object/array literals in deps always create new references.
Exercise 3 of 3
Live editor: a custom hook leaks a resize listener because it has no cleanup. Add the return function to fix the memory leak.
Task
The useWindowWidth hook attaches a resize listener but never removes it. Every time the component mounts, a new listener piles up — a classic memory leak. Add the cleanup function so the listener is removed when the component unmounts.
💡 Hint: useEffect can return a function. React calls it before the next effect run and on unmount. That is where you remove listeners, cancel timers, and abort fetches.