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:

Is the authoritative value provided via props?

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 value prop.

  • 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 value prop.

  • 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. ...

Ask