Reducer-Based Toggle Component
The reducer-based toggle component enhances UI toggles by centralizing behavioral logic within a reducer, which defines state transitions through a clear action vocabulary. This approach maintains a deterministic state shape, allowing for predictable behavior even as complexity increases. By dispatching actions rather than directly modifying state, the component becomes easier to test and extend. Best practices include keeping reducers pure, using stable action types, and ensuring a thin UI layer. This architecture prepares the component for future enhancements, such as external reducer injection, while promoting maintainability and scalability.
UI toggles often begin as trivial useState booleans, but as an application grows, they accumulate conditional rules, forcing the toggle on for certain roles, suppressing off transitions during loading, resetting after submission, and more. When this logic is scattered across event handlers and effects, behavior becomes unpredictable and difficult to maintain. The State Reducer pattern addresses this by moving behavioral logic out of the component body and into a reducer that explicitly defines state transitions. In this lesson, we build a reducer-driven toggle with explicit, testable state transitions. In the next lesson, we extend it to support external reducer overrides.
Reducer design for a toggle
A reducer-based component begins with a defined internal behavioral contract. For a simple toggle, the contract consists of the following elements:
State definition: The toggle maintains a minimal, deterministic state shape.
{ isOn: boolean }
This keeps state modeling simple and focused.
Action vocabulary: Actions describe what happened rather than what to do. A toggle typically supports:
"TOGGLE""TURN_ON""TURN_OFF"
These declarative labels allow the reducer to interpret intent without embedding logic in the UI.
Transition logic (Reducer): The reducer defines how each action transforms the current state.
Examples:
"TURN_ON"→{ isOn: true }"TURN_OFF"→{ isOn: false }"TOGGLE"→ flips the boolean
This makes all behavior auditable and easy to test.
State management via ...