Dual-Mode Reducer Components
Learn how a single reducer-driven component can operate in both controlled and uncontrolled modes without duplicating logic.
As components become more reusable across large React codebases, they must adapt to different ownership requirements. In simple contexts, a component should manage its own state internally, uncontrolled usage. However, in more complex workflows, analytics pipelines, multi-step forms, or coordinated UI systems, the parent must own the state entirely and control usage. Building two separate components for these scenarios leads to divergence, duplicated logic, and maintenance overhead. The architectural goal is therefore to design one component whose reducer defines the behavioral rules, while the state can live either internally or externally, depending on the props provided.
Dual-mode reducer design
The mode of a reducer-driven component is determined by one question:
If a value (or checked, count, etc.) prop is provided, the component operates in controlled mode. If not, it works in uncontrolled mode. The reducer always describes the same state transitions; only the state owner changes.
In an uncontrolled mode:
The consumer omits the
valueprop.The component initializes local reducer state via
useReducer.Event handlers dispatch internal actions (
dispatchInternal).The rendered value is read directly from the internal reducer state.
In a controlled mode:
The consumer supplies a
valueprop.The component ignores its internal reducer state for rendering.
Event handlers must not update internal state; instead, they call
onChange(nextValue).State updates occur only when the parent re-renders with the new
value. ...