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.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs