If I review a Junior Developer's PR, and I see 15 useEffect hooks in a single component, I know I'm about to see a bug.
useEffect is the Swiss Army Knife of React. It’s powerful, versatile, and easy to use. But just because you can use a knife to open a can of beans doesn't mean you should. It’s messy, dangerous, and there is a better tool for the job.
In 2026, with the maturity of React, using useEffect for basic logic is a code smell. It leads to "Effect Chains", where one update triggers an effect, which updates state, which triggers another effect, which renders... and suddenly your app feels sluggish.
Here are the three most common ways I see devs abusing useEffect and how to fix them.
1. Stop Using it for "Derived State"
This is the most common crime. You have firstName and lastName, and you want fullName.
The Bad Way (Using useEffect):
You create a state for fullName and use an effect to update it whenever the names change. This causes two renders: one for the name change, and one for the effect updating the full name.
The Senior Way:
Just calculate it during the render.
const fullName = firstName + ' ' + lastName;
If the calculation is expensive (like filtering a massive array), wrap it in useMemo. But never put it in state just to update it with an effect.
2. Stop Using it for User Events
I often see code where a developer wants to send an analytics event when a user buys an item.
The Bad Way:
They set isPurchased to true, then have a useEffect watching isPurchased to fire the analytics event.
The Senior Way:
Put the event in the Event Handler.
When the user clicks the "Buy" button, fire the analytics function inside that click handler.
Effects are for synchronization with external systems (like a server connection or the DOM). They are not for handling user interactions. If a user explicitly clicked something, handle the logic there.
3. Stop Using it for Data Fetching (Without a Plan)
React 18/19 strict mode taught us this lesson hard: effects fire twice in development.
The Bad Way:
Writing a raw fetch call inside useEffect without cleanup logic or race-condition handling.
The Senior Way:
In 2026, we use libraries like TanStack Query (React Query) or SWR. They handle caching, deduping, and background updates. If you must write it manually, you need to handle the cleanup function to cancel the request if the component unmounts.
The Mental Shift
The goal of a Senior React Dev isn't to write more hooks. It's to delete them.
Before you type useEffect, ask yourself:
Can I calculate this from existing props or state? (If yes, no Effect needed).
Is this happening because the user clicked something? (If yes, handle it in the event handler).
Is this actually synchronizing with an external system? (If yes, proceed).
Your future self (and your users) will thank you for the cleaner code.
Hi, I'm Frank Oge. I build high-performance software and write about the tech that powers it. If you enjoyed this, check out more of my work at frankoge.com
For further actions, you may consider blocking this person and/or reporting abuse

Top comments (0)