You A̶l̶m̶o̶s̶t̶ Never Need useReducer
Yashodhan Singh

Yashodhan Singh @dsfx3d

About: I am excited to share my experiences and connect with other developers here on dev.to! 🚀

Joined:
Mar 24, 2019

You A̶l̶m̶o̶s̶t̶ Never Need useReducer

Publish Date: Jun 11
1 1

Let’s stop pretending useReducer is some architectural upgrade over useState.

It’s not.

In the hands of most developers, it’s just overengineering theater. A costume.

An attempt to cosplay as a systems thinker in a CRUD world.

But here’s the truth:

If you’re reaching for useReducer in your React component, you're probably just adding ceremony to avoid writing setState.

Let’s talk about it.


🧠 Why Devs Fall for useReducer

It looks structured.
It feels scalable.
It smells testable.

It lets you write fancy things like:

dispatch({ type: 'UPDATE_FIELD', field: 'title', value: e.target.value });
Enter fullscreen mode Exit fullscreen mode

And now you feel like you're writing a framework instead of a component.

But you're not building a state machine.
You're updating a form input.

This isn't clever. It's LARPing.


💬 The Famous Interview Trauma

You've heard it:

“My friend was rejected from a frontend role because they used useState instead of useReducer 😞”

That anecdote makes the rounds every 3 months — usually paired with something like this:

const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const [startDate, setStartDate] = useState(null);
const [endDate, setEndDate] = useState(null);
Enter fullscreen mode Exit fullscreen mode

Then comes the critique:

Too many states!
No validation!
Inconsistent logic!
Not enterprisey enough!

So they slap on a reducer:

const [event, updateEvent] = useReducer((prev, next) => {
  // This section will be bad for
  // your mental health in the real world
  const newEvent = { ...prev, ...next };

  if (newEvent.startDate > newEvent.endDate) {
    newEvent.endDate = newEvent.startDate;
  }

  if (newEvent.title.length > 100) {
    newEvent.title = newEvent.title.substring(0, 100);
  }

  return newEvent;
}, {
  title: '',
  description: '',
  startDate: null,
  endDate: null,
});
Enter fullscreen mode Exit fullscreen mode

Congratulations.
You’ve replaced readable logic with a pseudo–Redux wormhole to feel more "correct."


💡 Why Coupling Validation with State Stinks

You're baking validation logic into the state update mechanism. That means:

  • Every state change must trigger validation — even when it shouldn't
  • You can’t test validation separately
  • You can’t control when or how validation happens
  • You’ve locked logic into an opaque reducer blob

Validation is not a reducer's job. A reducer should handle transitions, not rules.


✅ The Clean Way (That Just Works)

Let’s write boring, effective, adult code:


function useForm(initialValues) {
  const [title, setTitle] = useState(initialValues.title);
  const [description, setDescription] = useState(initialValues.description);
  const [startDate, setStartDate] = useState(initialValues.startDate);
  const [endDate, setEndDate] = useState(initialValues.endDate);

  return {
    title,
    setTitle,
    description,
    setDescription,
    startDate,
    setStartDate,
    endDate,
    setEndDate,
  };
}

const {
  setTitle,
  setDescription,
  setStartDate,
  setEndDate,
  ...event,
} = useForm({
  title: '',
  description: '',
  startDate: null,
  endDate: null,
});

const validateEvent = (event) => {
  const errors = {};
  if (event.startDate > event.endDate) {
    errors.date = 'End date must be after start date';
  }
  if (event.title.length > 100) {
    errors.title = 'Title must be under 100 characters';
  }
  return errors;
};
Enter fullscreen mode Exit fullscreen mode

You can now:

  • Validate on blur
  • Show errors inline
  • Test validateEvent independently
  • Reuse the same validation in the backend
  • Extend logic without digging through reducer guts

This is code that’s actually maintainable.


🤡 The Real Reason People Push useReducer

You are probably an influencers trying to sell your "How to be a 10x dev? I know, you don't" course when your only real skill is clearing interviews.

You exploit the insecurities of innocent junior devs without providing them any real value in return and by making them feel:

  • insecure about writing “basic” code.
  • useState looks amateur
  • Abstracting everything into a reducer makes it “professional”
  • More indirection = better architecture

It’s the same mindset that leads to:

  • Overuse of design patterns
  • Creating types.ts files for three enums
  • Wrapping simple logic in ten layers of abstraction

You're not a worse dev for writing useState.
You’re a better one for knowing when not to reach for complexity.


🧠 When useReducer Actually Belongs

Let’s be fair. Here’s when it makes sense:

✅ Finite State Machines (e.g., multi-step wizards)
✅ Undo/Redo logic
✅ Pure state transitions you want to extract + test
✅ Shared reducer logic across multiple components
✅ You're modeling explicit transitions, not just storing values

If that’s not you, and you’re still using useReducer, ask yourself:

Am I solving a real problem?
Or just inventing stuff to feel clever?


✍️ The Rule of Thumb

useState is for values.
Custom hooks are for reuse.
useReducer is for transitions.

Write code that’s easy to read, not code that performs intellectual gymnastics.

Break this rule of thumb if it gets in the way.


🔥 Final Thought

You don’t get a promotion for writing dispatch().

You don’t become a better engineer by mimicking Redux on your delete confirmation modal.

You become a better engineer by writing clear, boring, durable code your teammates can understand without context.

So unless your state has explicit transitions, interdependencies, or reversibility — just use useState.

Don't be a sheep 🐑.
You almost never need useReducer.

Comments 1 total

  • Richard
    RichardJun 11, 2025

    Hey blockchain user! snag your instant $50 worth of crypto in DuckyBSC rewards quick! — Claim your tokens! Web3 wallet required to access airdrop. 👉 duckybsc.xyz

Add comment