Building a 3-State Switch in React

by iamvkr on

Introduction:

A quick walkthrough of implementing a 3-state switch in React—starting with a basic if-else approach and refining it into a clean, scalable solution using modulo arithmetic.


The Problem

Sometimes a boolean just isn’t enough. Think of a checkbox that can be unchecked, intermediate, or checked.
In React, this usually means cycling through a fixed set of states on each click.

Let’s explore a few ways to do that—starting simple and ending clean.


Step 1: The Classic (If-Else) Approach

The most straightforward way is to manually move from one state to the next using if / else.

const [currentStateIndex, setCurrentStateIndex] = useState(0);

const handleChangeState = () => {
  if (currentStateIndex === 0) {
    setCurrentStateIndex(1);
  } else if (currentStateIndex === 1) {
    setCurrentStateIndex(2);
  } else {
    setCurrentStateIndex(0);
  }
};

return (
    <div>
      <button onClick={handleChangeState}>
        Current state: {states[currentState]} : {currentState}
      </button>
    </div>
)

✅ Easy to understand
❌ Not scalable (adding more states gets messy fast)


Step 2: Slight Improvement

(Array + shorter if-else)

Next, we introduce an array of states and cycle through them using math.

const states = ["unchecked", "intermediate", "checked"];
const [currentStateIndex, setCurrentStateIndex] = useState(0);

const handleChangeState = () => {
    if (currentStateIndex === states.length - 1) {
      setcurrentStateIndex(0);
    } else {
      setcurrentStateIndex((prev) => prev + 1);
    }
  };

✅ Much cleaner

This works fine in simple cases, and many developers stop here.


(Functional Update + Modulo)

The most robust approach uses React’s functional state update, ensuring you always work with the latest value.

const states = ["unchecked", "intermediate", "checked"];

const handleChangeState = () => {
  setCurrentStateIndex(prev => (prev + 1) % states.length);
};

✅ Clean
✅ Scalable
✅ Safe with batched or async updates.

Why Use Modulo (%):

The modulo operation ((prev + 1) % states.length) ensures that you can easily add more states in the future without having to change the logic for handling the transition. The modulo operation effectively loops through the states, so if you had 4 states, it would cycle between 0, 1, 2, 3, and back to 0 seamlessly.

This pattern is short, expressive, and future-proof.


Final Thoughts

  • If-else works, but doesn’t scale
  • Direct state math is cleaner, but could be better
  • Functional update + modulo is the sweet spot

If you’re cycling through states in React, modulo arithmetic with a functional updater is usually the best tool for the job.