JAVASCRIPT
Manage Complex Form State with React's `useReducer` Hook
Master React's `useReducer` hook for robust and predictable state management in complex forms. Enhance code organization and maintainability for multi-field inputs.
import React, { useReducer } from 'react';
const initialState = {
username: '',
email: '',
password: '',
confirmPassword: '',
errors: {}
};
function formReducer(state, action) {
switch (action.type) {
case 'FIELD_CHANGE':
return {
...state,
[action.field]: action.value,
errors: { ...state.errors, [action.field]: undefined } // Clear error on change
};
case 'SET_ERROR':
return {
...state,
errors: { ...state.errors, [action.field]: action.message }
};
case 'RESET_FORM':
return initialState;
default:
return state;
}
}
function UserRegistrationForm() {
const [formState, dispatch] = useReducer(formReducer, initialState);
const { username, email, password, confirmPassword, errors } = formState;
const handleChange = (e) => {
dispatch({
type: 'FIELD_CHANGE',
field: e.target.name,
value: e.target.value
});
};
const validateForm = () => {
let isValid = true;
if (!username) {
dispatch({ type: 'SET_ERROR', field: 'username', message: 'Username is required' });
isValid = false;
}
if (!email.includes('@')) {
dispatch({ type: 'SET_ERROR', field: 'email', message: 'Invalid email format' });
isValid = false;
}
if (password.length < 6) {
dispatch({ type: 'SET_ERROR', field: 'password', message: 'Password must be at least 6 characters' });
isValid = false;
}
if (password !== confirmPassword) {
dispatch({ type: 'SET_ERROR', field: 'confirmPassword', message: 'Passwords do not match' });
isValid = false;
}
return isValid;
};
const handleSubmit = (e) => {
e.preventDefault();
if (validateForm()) {
console.log('Form Submitted Successfully:', { username, email, password });
dispatch({ type: 'RESET_FORM' });
alert('Registration successful!');
} else {
console.log('Form has errors:', errors);
}
};
const inputStyle = {
display: 'block',
margin: '10px 0',
padding: '8px',
width: '100%',
boxSizing: 'border-box'
};
const errorStyle = {
color: 'red',
fontSize: '0.8em'
};
const formContainerStyle = {
maxWidth: '400px',
margin: '20px auto',
padding: '20px',
border: '1px solid #ccc',
borderRadius: '8px'
};
const buttonStyle = {
padding: '10px 15px',
fontSize: '16px',
cursor: 'pointer',
marginTop: '15px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '5px'
};
return (
<form onSubmit={handleSubmit} style={formContainerStyle}>
<h2>User Registration</h2>
<div>
<label>
Username:
<input
type="text"
name="username"
value={username}
onChange={handleChange}
style={inputStyle}
/>
</label>
{errors.username && <p style={errorStyle}>{errors.username}</p>}
</div>
<div>
<label>
Email:
<input
type="email"
name="email"
value={email}
onChange={handleChange}
style={inputStyle}
/>
</label>
{errors.email && <p style={errorStyle}>{errors.email}</p>}
</div>
<div>
<label>
Password:
<input
type="password"
name="password"
value={password}
onChange={handleChange}
style={inputStyle}
/>
</label>
{errors.password && <p style={errorStyle}>{errors.password}</p>}
</div>
<div>
<label>
Confirm Password:
<input
type="password"
name="confirmPassword"
value={confirmPassword}
onChange={handleChange}
style={inputStyle}
/>
</label>
{errors.confirmPassword && <p style={errorStyle}>{errors.confirmPassword}</p>}
</div>
<button type="submit" style={buttonStyle}>Register</button>
<button type="button" onClick={() => dispatch({ type: 'RESET_FORM' })} style={{...buttonStyle, marginLeft: '10px', backgroundColor: '#6c757d'}}>Reset</button>
</form>
);
}
export default UserRegistrationForm;
How it works: This example uses `useReducer` to manage the state of a complex registration form, including multiple input fields and error messages. The `formReducer` function defines how state transitions occur based on dispatched actions (`FIELD_CHANGE`, `SET_ERROR`, `RESET_FORM`), centralizing the state logic and making it more predictable and testable than multiple `useState` calls.