How to Use useReducer for Form State in React
Use
useReducer to manage form state by defining a reducer function that updates state based on action types, and dispatch actions on input changes. This approach centralizes state logic and is ideal for complex forms with multiple fields.Syntax
The useReducer hook takes two main arguments: a reducer function and an initial state. The reducer function receives the current state and an action, then returns the new state. You use dispatch to send actions that update the state.
For form state, the reducer typically handles actions like updating input values or resetting the form.
javascript
const [state, dispatch] = useReducer(reducer, initialState); function reducer(state, action) { switch (action.type) { case 'UPDATE_FIELD': return { ...state, [action.field]: action.value }; case 'RESET': return initialState; default: return state; } }
Example
This example shows a simple form with two inputs: name and email. The useReducer hook manages the form state. When you type in the inputs, the state updates accordingly. A reset button clears the form.
javascript
import React, { useReducer } from 'react'; const initialState = { name: '', email: '' }; function reducer(state, action) { switch (action.type) { case 'UPDATE_FIELD': return { ...state, [action.field]: action.value }; case 'RESET': return initialState; default: return state; } } export default function Form() { const [state, dispatch] = useReducer(reducer, initialState); const handleChange = (e) => { dispatch({ type: 'UPDATE_FIELD', field: e.target.name, value: e.target.value }); }; const handleReset = () => { dispatch({ type: 'RESET' }); }; return ( <form> <label htmlFor="name">Name:</label> <input id="name" name="name" value={state.name} onChange={handleChange} aria-label="Name input" /> <label htmlFor="email">Email:</label> <input id="email" name="email" value={state.email} onChange={handleChange} aria-label="Email input" /> <button type="button" onClick={handleReset}>Reset</button> <p><strong>Current State:</strong> {JSON.stringify(state)}</p> </form> ); }
Output
A form with two text inputs labeled 'Name' and 'Email', a Reset button, and below it the current state displayed as JSON updating as you type.
Common Pitfalls
- Mutating state directly: Always return a new state object in the reducer to avoid bugs.
- Not handling all action types: Always include a default case in the reducer to return current state.
- Forgetting to set input
nameattributes: The reducer usesaction.fieldto update state, so inputs must have matchingnameattributes. - Not using
dispatchproperly: Always calldispatchwith an action object, not just a value.
javascript
/* Wrong: Mutating state directly */ function reducer(state, action) { switch (action.type) { case 'UPDATE_FIELD': state[action.field] = action.value; // ❌ mutates state return state; default: return state; } } /* Right: Return new state object */ function reducer(state, action) { switch (action.type) { case 'UPDATE_FIELD': return { ...state, [action.field]: action.value }; default: return state; } }
Quick Reference
useReducer for form state cheat sheet:
initialState: Object with form fields and initial values.reducer(state, action): Handles actions like 'UPDATE_FIELD' and 'RESET'.dispatch({ type, field, value }): Updates specific field.- Use input
namematching state keys for easy updates. - Always return new state object in reducer.
Key Takeaways
Use useReducer to centralize and simplify form state updates in React.
Define a reducer that returns new state objects based on action types.
Dispatch actions on input changes with field name and value.
Always include a default case in your reducer to return current state.
Ensure input elements have name attributes matching state keys.