Why this concept matters
A real form must reject empty input and update the screen without rewriting the whole component. Start with a controlled input, then move related updates into a reducer.
A multi-field issue form needs predictable validation and state changes. You will learn: explain the idea, follow the execution flow, read a compact example and try one realistic decision. Basic React components, props and useState are helpful; this Byte also works as a standalone introduction.
Start with a familiar scenario
A form is a conversation: the user supplies values, the app checks them, and only valid data is accepted.
Vocabulary: controlled field, validation, reducer, action, state transition.
Understand the core concept
Think of a reducer as a clerk receiving a clear instruction: add this issue. It takes the current records plus that instruction and returns a new record list. The reducer does not reach into the browser or call an API.
Controlled inputs receive their value from state and report edits with onChange. Validation checks inputs and shows recovery guidance. useReducer groups related state updates as explicit actions; reducers must be pure.
When not to use it: Select the simplest React feature that solves the actual problem. An advanced API or Hook is not a requirement for every component.
Architecture and execution flow
Trace the information as it moves through the application. Every stage has a specific purpose.
VISUAL EXPLAINER · BYTE 1
Follow the React execution path
Stage 1: Form input. Trace the result before continuing.
01Input → controlled state → validation → action → reducer → screenInteractive decision lab
Choose an answer to a realistic development situation. Review the resulting explanation before writing code.
LEARN BY DECIDING
A blank issue title is submitted.
Try It Yourself — code and browser output
TRY IT YOURSELF · ADVANCED REACT 1/5
Code → experiment → visible output
A working issue form using controlled inputs and useReducer.
import { useReducer, useState } from 'react';type Issue = { id: number; title: string; priority: 'Low' | 'High' };type Action = { type: 'add'; issue: Issue };function reducer(state: Issue[], action: Action): Issue[] { switch (action.type) { case 'add': return [...state, action.issue]; }}export default function App() { const [issues, dispatch] = useReducer(reducer, []); const [title, setTitle] = useState(''); const [error, setError] = useState(''); function addIssue() { if (!title.trim()) { setError('Title is required'); return; } dispatch({ type: 'add', issue: { id: Date.now(), title: title.trim(), priority: 'Low' } }); setTitle(''); setError(''); } return <main> <h1>Issue Desk</h1> <label htmlFor="issue">Issue title</label> <input id="issue" value={title} onChange={e => setTitle(e.target.value)} /> {error && <p role="alert">{error}</p>} <button onClick={addIssue}>Add issue</button> <ul>{issues.map(i => <li key={i.id}>{i.title}</li>)}</ul> </main>;}Interactive output simulation
Submit an empty title, then enter a title and select a priority.
- Fix sign-in issue · High
- Update help page · Low
Why this happens: The browser first validates the form. A valid submission dispatches an action; the reducer returns a new array and React renders the added issue. The right side is a learning simulator, not a compiled execution environment. Copy the code into a configured React project to execute it.
Experiment: Leave the title blank and press Add issue. Notice that the list does not change. Now enter Printer not working, choose High and submit. The new item should appear once.
Guided code walkthrough
Step 1 — Identify the inputs and the expected output. A multi-field issue form needs predictable validation and state changes.
Step 2 — Read the implementation. The example is intentionally small; it isolates the concept before introducing additional application architecture.
01type Issue = { title: string; priority: 'low' | 'high' };02type State = { issues: Issue[] };03type Action = { type: 'added'; issue: Issue };04function reducer(state: State, action: Action): State {05switch (action.type) {06case 'added': return { issues: [...state.issues, action.issue] };07}08}
Step 3 — Predict the browser result. A valid issue is added; an empty title is rejected.
Step 4 — Explain the execution. Input; then controlled state; then validation; then action; then reducer; then screen.
Step 5 — Verify. Run the example in a React/TypeScript project with the appropriate installed package or mock API. The purpose is understanding behavior, not copy-pasting an unexplained application.
Common mistakes and recovery
Mutating reducer state; hiding field errors; using a reducer for one simple boolean.
When behavior is surprising, verify the inputs and first observable failure. Check browser-console warnings, network responses and visible error states before adding complexity.
How developers use this at work
This pattern appears in customer portals, internal dashboards and SaaS products. Developers use it to make interfaces predictable and maintainable. QA engineers test the user-facing outcome, while product teams define valid states and errors.
What users see versus system behavior
| User-visible experience | Underlying behavior |
|---|---|
| A valid issue is added; an empty title is rejected. | Input → controlled state → validation → action → reducer → screen |
| Recovery from a failure | The application handles an invalid input, request or state explicitly |
Practice task
Create a title input with required validation and a priority selector. Submit empty and valid values to compare results.
Success check: describe the input, the React action and the output. Try the failure case once, then explain the recovery.
Interview Bit
When should you choose useReducer over useState? Use useState for a few independent values. Choose a reducer when several related updates benefit from explicit actions and centralized transition logic.
Key Takeaways
- Controlled form values come from React state.
- onChange updates the draft value a user is editing.
- Validation runs before accepting a submission.
- useReducer returns a state value and a dispatch function.
- An action describes what happened rather than mutating state.
- A reducer returns a new state and must be pure.
- Error messages should explain exactly how to recover.
- Not every form needs useReducer; prefer simple state when sufficient.
Knowledge Check and Primary Sources
FAQ: Is this technique required in every React component? No; apply it only when the corresponding problem exists.
FAQ: Can it be tested without a real backend? Yes, with local examples and mock responses.
FAQ: Should learners understand the underlying JavaScript? Yes. Hooks and libraries build on ordinary functions, arrays, objects and promises.
PRACTISE AND CHECK
Knowledge Check · 5 questions
Choose one answer for each question. Submit to reveal your score and feedback.
0 of 5 answered
Primary sources: Official reference 1 · Official reference 2.