React Hooks feel magical at first. A few useStates, a useEffect, maybe a useMemo, and suddenly your component is alive. But as apps grow, small hook mistakes quietly turn into performance bugs, stale state, and impossible-to-debug behavior.
If you’ve ever said “Why is this effect running again?” or “Why does this value feel one render behind?”, this post is for you.
Let’s walk through the most common Hook mistakes I see in production React apps—and how experienced teams avoid them.
1. Treating useEffect Like a Lifecycle Dumping Ground
This is the classic one.
useEffect(() => {
fetchUser();
trackAnalytics();
setIsReady(true);
}, []);
At first glance, this feels fine. But what’s actually happening?
You’ve mixed:
- Data fetching
- Side effects
- State transitions
…into one untestable blob.
Why this bites later
- Dependencies become unclear
- Refactors accidentally break behavior
- Effects grow instead of being replaced
The fix: one effect, one responsibility
useEffect(() => {
fetchUser();
}, []);
useEffect(() => {
trackAnalytics();
}, []);
useEffect(() => {
setIsReady(true);
}, []);
It feels verbose—but clarity beats cleverness every time.
2. Ignoring the Dependency Array (or Fighting It)
If you’ve ever done this, no judgment:
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => {
doSomething(value);
}, []);
You’re telling React: “I know better.”
Most of the time… you don’t 😄
What actually goes wrong
- Effects read stale values
- Bugs appear only after re-renders
- Logic breaks when props change
The fix: embrace dependencies
useEffect(() => {
doSomething(value);
}, [value]);
If adding a dependency causes infinite loops, that’s a design smell, not a React problem.
3. Overusing useMemo and useCallback
Hooks for performance feel responsible. Until they’re everywhere.
const computedValue = useMemo(() => {
return expensiveCalculation(data);
}, [data]);
The truth
-
useMemois a cache, not a guarantee - It adds complexity and memory overhead
- Most computations don’t need it
When you actually need it
Use useMemo or useCallback only if:
- The calculation is expensive
- The component re-renders often
- You’ve measured a problem
Otherwise, let React re-run the function. It’s fast.
4. Storing Derived State in useState
This one causes subtle bugs.
const [fullName, setFullName] = useState('');
useEffect(() => {
setFullName(`${firstName} ${lastName}`);
}, [firstName, lastName]);
Now you have:
- Source state
- Derived state
- Synchronization logic
All for something React can compute instantly.
The fix: derive during render
const fullName = `${firstName} ${lastName}`;
If state can be calculated from props or other state, don’t store it.
5. Mutating State Objects Accidentally
React state must be immutable. But it’s easy to forget.
// ❌ Mutates existing object
user.profile.name = 'New Name';
setUser(user);
This may not re-render at all.
The fix: always create new references
setUser(prev => ({
...prev,
profile: {
...prev.profile,
name: 'New Name',
},
}));
React compares references.
If the reference doesn’t change, neither does the UI.
6. Putting Too Much Logic Inside Components
Hooks don’t mean “everything goes in the component.”
function Dashboard() {
const data = useData();
const filtered = data.filter(...);
const sorted = filtered.sort(...);
const grouped = groupBy(sorted);
return <UI grouped={grouped} />;
}
This gets ugly fast.
The fix: extract custom hooks
function useDashboardData() {
const data = useData();
return useMemo(() => {
return groupBy(sort(filter(data)));
}, [data]);
}
Your component becomes:
- Smaller
- Easier to test
- Easier to reuse
Hooks are abstractions, not decorations.
7. Forgetting That Hooks Run on Every Render
Hooks are not events. They are part of rendering.
const value = useExpensiveThing();
This runs every render unless you control it.
Mental model that helps
- Rendering should be pure
- Effects handle side effects
- Memoization is an optimization, not a default
If a hook does too much work, it’s probably doing the wrong job.
Key Takeaway
React Hooks are powerful—but only if you respect their model:
- Effects are for side effects, not logic dumps
- Dependencies are your friend
- Derived state should stay derived
- Performance hooks are tools, not habits
- Clean abstractions beat clever tricks
Most “weird React bugs” aren’t React bugs at all.
They’re mental model mismatches.
Discussion
What’s the most confusing Hook bug you’ve ever debugged—and what was the actual root cause once you figured it out?



Top comments (0)