Sitemap

Why I Stopped Reaching for useEffect (And You Probably Should Too)

--

  • Page mounts? useEffect.
  • Props change? useEffect.
  • Need to compute something? You guessed it — useEffect.

Then I sat down and read React’s “You Might Not Need an Effect” guide from start to finish. It completely changed how I think about React.

I realized that a large percentage of the effects I had written weren’t necessary. Some of them were even making my applications slower, more complex, and harder to debug.

Here’s the mental model I use today.

The Three Things useEffect Is Usually the Wrong Tool For

1. Derived State

One of the most common mistakes is using an effect to compute state from other state. Instead of storing derived values, calculate them during render.

Instead of this:

const [fullName, setFullName] = useState("");
useEffect(() => {
setFullName(`${firstName} ${lastName}`);
}, [firstName, lastName]);

Do this:

const fullName = `${firstName} ${lastName}`;

The first version causes an unnecessary render because React has to render once, run the effect, update state, and render again.

The second version produces the exact same result with less work.

2. Transforming Props

Another common pattern is copying props into local state.

For example:

const [items, setItems] = useState([]);
useEffect(() => {
setItems(props.items.filter(item => item.active));
}, [props.items]);

Instead, derive the value directly:

const items = useMemo(
() => props.items.filter(item => item.active),
[props.items]
);

And if the computation isn’t expensive, you probably don’t even need useMemo:

const items = props.items.filter(item => item.active);

Remember: useMemo is a performance optimization—not a default pattern.

3. Resetting State When Something Changes

Suppose you have a profile editor that should reset whenever the userId changes.

Get Sachinpundir’s stories in your inbox

Join Medium for free to get updates from this writer.

Many developers write:

useEffect(() => {
setDraft("");
}, [userId]);

A cleaner approach is to let React create a fresh component instance:

<ProfileEditor key={userId} userId={userId} />

Changing the key tells React to remount the component, giving you brand-new state automatically.

No manual reset.
No cleanup.
No race conditions.

When useEffect Is Actually the Right Choice

Effects exist for one purpose:

Synchronizing React with systems outside of React.

Good examples include:

  • Opening or closing a WebSocket connection
  • Adding and removing event listeners
  • Sending analytics events
  • Reading from or writing to localStorage
  • Imperatively focusing a DOM element
  • Integrating with third-party libraries

If your effect doesn’t interact with something outside React, there’s a good chance you don’t need it.

The One Question That Changed How I Write React

Before writing any useEffect, I now ask myself one simple question:

What would happen if I deleted this effect and computed everything during render instead?

If the answer is: “Nothing.” Then I remove the effect.

If the answer is:“I’d lose a subscription, a DOM interaction, or synchronization with an external system.” Then I keep it.

This one question has eliminated a surprising number of unnecessary effects from my codebase.

The result?

  • Fewer renders
  • Less state to manage
  • Fewer synchronization bugs
  • Simpler components that are easier to understand months later

Final Thoughts

If you’ve been writing React for a few years, there’s a good chance you learned useEffect before React's newer guidance existed.

Take twenty minutes and read “You Might Not Need an Effect.”

It completely changed the way I structure React components, and it’s probably the highest-leverage piece of React documentation I’ve read.

Sometimes the fastest React code isn’t about adding another hook.

It’s about realizing you didn’t need one in the first place.

Thanks for reading! If this article helped you rethink useEffect, I'd love to hear what patterns you've stopped using in modern React.

--

--