Next.js & React Pitfall Questions (With Fixes)
❌ useEffect Infinite Loop
Problem
useEffect(() => {
setCount(count + 1);
}, [count]);
Why it’s wrong
setCount updates count, which triggers the effect again → infinite loop.
Fix
useEffect(() => {
setCount(prev => prev + 1);
}, []);
❌ Stale Closure
Problem
useEffect(() => {
setTimeout(() => {
console.log(count);
}, 1000);
}, []);
Why it’s wrong
The effect captures the initial value of count.
Fix
useEffect(() => {
const id = setTimeout(() => {
console.log(count);
}, 1000);
return () => clearTimeout(id);
}, [count]);
❌ Conditional Hooks
Problem
if (isLoggedIn) {
useEffect(() => {
fetchData();
}, []);
}
Why it’s wrong Hooks must be called unconditionally and in the same order.
Fix
useEffect(() => {
if (isLoggedIn) {
fetchData();
}
}, [isLoggedIn]);
❌ Async useEffect
Problem
useEffect(async () => {
await fetchData();
}, []);
Why it’s wrong
useEffect must return either nothing or a cleanup function — not a Promise.
Fix
useEffect(() => {
const load = async () => {
await fetchData();
};
load();
}, []);
❌ Missing Dependency
Problem
useEffect(() => {
fetchData(id);
}, []);
Why it’s wrong
id is used but not listed → stale data bug.
Fix
useEffect(() => {
fetchData(id);
}, [id]);
⚠️ State Pitfalls
❌ setState Using Old State
Problem
setCount(count + 1);
setCount(count + 1);
Why it’s wrong Both updates read the same stale value.
Fix
setCount(prev => prev + 1);
setCount(prev => prev + 1);
❌ Derived State Anti-Pattern
Problem
const [fullName, setFullName] = useState(
firstName + " " + lastName
);
Why it’s wrong State derived from state causes sync bugs.
Fix
const fullName = `${firstName} ${lastName}`;
❌ Using Ref Instead of State
Problem
const count = useRef(0);
return <p>{count.current}</p>;
Why it’s wrong Refs don’t trigger re-renders.
Fix
const [count, setCount] = useState(0);
⚠️ Performance Pitfalls
❌ Wrong Key Usage
Problem
items.map((item, index) => (
<li key={index}>{item}</li>
));
Why it’s wrong Index keys break reconciliation on reorder.
Fix
items.map(item => (
<li key={item.id}>{item.name}</li>
));
❌ useMemo With Empty Deps
Problem
const value = useMemo(() => compute(data), []);
Why it’s wrong
data changes won’t recompute.
Fix
const value = useMemo(() => compute(data), [data]);
❌ useCallback Trap
Problem
const handleClick = useCallback(() => {
console.log(count);
}, []);
Why it’s wrong
count is frozen to its initial value.
Fix
const handleClick = useCallback(() => {
console.log(count);
}, [count]);
❌ Memoizing JSX
Problem
const view = useMemo(() => <Child />, []);
Why it’s wrong JSX creation is cheap — this adds complexity for nothing.
Fix
<Child />
❌ React.memo False Optimization
Problem
const Child = React.memo(({ user }) => {
return <p>{user.name}</p>;
});
<Child user= />
Why it’s wrong New object reference → re-render anyway.
Fix
const user = useMemo(() => ({ name: "John" }), []);
<Child user={user} />
⚠️ Async & Data Pitfalls
❌ Race Condition
Problem
useEffect(() => {
fetchUser(id).then(setUser);
}, [id]);
Why it’s wrong Older requests can overwrite newer ones.
Fix
useEffect(() => {
let active = true;
fetchUser(id).then(user => {
if (active) setUser(user);
});
return () => {
active = false;
};
}, [id]);
⚠️ Context Pitfalls
❌ Context Re-render Explosion
Problem
<AuthContext.Provider value=>
Why it’s wrong New object → all consumers re-render.
Fix
const value = useMemo(() => ({ user, logout }), [user, logout]);
<AuthContext.Provider value={value}>
✅ Final Thought
Most React / Next.js bugs aren’t syntax issues — they’re state, closure, and lifecycle misunderstandings.
If you can explain why these break and how to fix them, you’re already thinking at a senior level.