Consider this React functional component using hooks:
import React, { useState, useEffect } from 'react';
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('Effect runs');
});
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}What will be logged to the console when the component first appears and each time the button is clicked?
import React, { useState, useEffect } from 'react'; function Counter() { const [count, setCount] = useState(0); useEffect(() => { console.log('Effect runs'); }); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }
Think about when useEffect runs if no dependency array is provided.
Without a dependency array, useEffect runs after every render, including the first mount and every update.
Look at this React component:
import React, { useState } from 'react';
function Clicker() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
setCount(count + 1);
}
return (
<div>
<p>Count: {count}</p>
<button onClick={handleClick}>Click me twice</button>
</div>
);
}What will the count show after clicking the button once?
import React, { useState } from 'react'; function Clicker() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); setCount(count + 1); } return ( <div> <p>Count: {count}</p> <button onClick={handleClick}>Click me twice</button> </div> ); }
Remember that state updates may be batched and use the current state value.
Both setCount calls use the same stale count value (0), so the count increments only once to 1.
Consider this React component:
import React, { useEffect } from 'react';
function Timer() {
useEffect(() => {
const id = setInterval(() => console.log('tick'), 1000);
return () => clearInterval(id);
}, []);
return <div>Timer running</div>;
}But when the component unmounts, 'tick' keeps logging every second. Why?
import React, { useEffect } from 'react'; function Timer() { useEffect(() => { const id = setInterval(() => console.log('tick'), 1000); return () => clearInterval(id); }, []); return <div>Timer running</div>; }
Think about when cleanup functions run in React.
Cleanup functions run only when the component unmounts or before re-running the effect. If the component stays mounted, cleanup won't run.
Which code snippet correctly fetches data only once when the component mounts?
Consider how dependency arrays control effect execution.
Option D runs fetchData once on mount because of the empty dependency array. Option D runs on every render. Option D runs when fetchData changes (usually every render if not memoized). Option D passes fetchData directly, which is not a function call and may cause unexpected behavior.
Consider this React component:
import React, { useState, useEffect } from 'react';
function Loop() {
const [count, setCount] = useState(0);
useEffect(() => {
setCount(count + 1);
});
return <div>Count: {count}</div>;
}What will happen when this component renders?
import React, { useState, useEffect } from 'react'; function Loop() { const [count, setCount] = useState(0); useEffect(() => { setCount(count + 1); }); return <div>Count: {count}</div>; }
Think about what happens when state updates trigger re-renders inside useEffect with no dependencies.
Without a dependency array, useEffect runs after every render. Updating state inside it causes another render, triggering useEffect again, causing an infinite loop.