Skip to content

Repository files navigation

🎣 You might not need an effect — derived state in React

An interactive demo of the single most common useEffect mistake: using an effect to compute state from other state, instead of just computing it during render. Live render counters make the cost obvious.

▶ Live: https://derived-state.pages.dev/

The anti-pattern

const [first, setFirst] = useState("");
const [last,  setLast]  = useState("");
const [fullName, setFullName] = useState("");

useEffect(() => {
  setFullName(first + " " + last);   // 🐞 mirror + sync
}, [first, last]);

Every keystroke triggers two renders — one for the input change, then the effect runs and calls setFullName, forcing another. And for one frame fullName is stale (it still holds the previous render's value) until the effect catches up. In the demo, typing a few characters pushes this panel's render count to roughly double the other's.

The fix is to delete the effect

const [first, setFirst] = useState("");
const [last,  setLast]  = useState("");

const fullName = first + " " + last;   // ✅ just derive it

One render per keystroke, always correct, no duplicate state, no effect. If the computation is expensive, reach for useMemo(() => heavy(a, b), [a, b]) — still not an effect.

When you don't need an effect

  • Deriving data from props/state → compute during render (memoize if expensive).
  • Responding to an event → do it in the event handler, not an effect.
  • Resetting state when a prop changes → pass a key to remount, don't watch the prop.
  • Caching an expensive resultuseMemo, not state + effect.

When you do need one

Effects are for synchronizing with systems outside React: fetching data, subscriptions, timers, manually touching the DOM, sending analytics. The tell: if an effect's whole body is setState from other state/props, delete it — that value belongs in render.

This mirrors React's own You Might Not Need an Effect guidance; the demo just makes the render cost visible.

Stack

React 19 · TypeScript · Vite. StrictMode is off so the render counts are real, not the dev-mode double-invoke.

Run locally

npm install
npm run dev

License

MIT © 2026 dev48vdev48v.infy.uk

About

Interactive React demo of the most common useEffect anti-pattern — syncing derived state with an effect (extra renders + stale frames) vs computing it during render. Live render counters prove it. From React's 'You Might Not Need an Effect'. React 19 + TS + Vite.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages