Mahamudul Hasan Rubel
HomeBlogCoursesAboutProjectsSkillsExperiencePhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • Blog
  • Courses
  • About
  • Projects
  • Skills
  • Experience
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
Lesson 32 of the Intermediate React: Hooks, State & Data Patterns course
ReactJune 26, 20263 min read

Optimizing Form Submissions: UX, Errors, and API Handling

Learn to optimize form submissions in React by disabling buttons during requests, handling server errors, and providing clear, actionable user feedback.

ReactFormsUXAPIWeb Developmentjavascriptfrontend

Previously in this course, we explored Real-time Form Validation in React: A Pro Guide and mastered Controlled vs Uncontrolled Components: React Form Mastery. Now that our inputs are validated and controlled, we must address the "black box" phase of the user experience: the moment a user clicks "Submit" and waits for the API to respond.

A great user interface doesn't just process data; it communicates status. Without clear feedback, users often click buttons multiple times, leading to duplicate database entries and frustration.

Mastering Form Submission UX

When building professional interfaces, a submission lifecycle consists of three distinct states: Idle, Submitting, and Error/Success. Managing these states isn't just about showing a spinner; it's about protecting your application's integrity.

Disabling Buttons During Submission

The most common mistake in junior-level React forms is allowing a user to trigger a second POST request while the first one is still in flight.

By disabling the submit button, you achieve two things:

  1. Prevents duplicate requests: You eliminate race conditions that cause data corruption.
  2. Visual feedback: The browser's default disabled styling provides an immediate cue that the action is "in progress."

Handling Server-Side Errors

Even with perfect client-side validation, your API will eventually return a 400 or 500 error. Your form needs to catch these, map them to specific UI fields, or display a global "toast" notification. We'll use a standard try/catch block within our submission handler to ensure these failures don't crash the UI.

Worked Example: A Robust Submission Pattern

Let's apply these principles to our dashboard's profile settings form.

JSX
import { useState } from CE9178">'react';

const ProfileForm = () => {
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [error, setError] = useState(null);

  const handleSubmit = async (event) => {
    event.preventDefault();
    setIsSubmitting(true);
    setError(null);

    try {
      const response = await fetch(CE9178">'/api/user/profile', {
        method: CE9178">'POST',
        body: JSON.stringify({ /* form data */ }),
      });

      if (!response.ok) {
        throw new Error(CE9178">'Failed to update profile. Please try again.');
      }
      
      // Handle success
    } catch (err) {
      setError(err.message);
    } finally {
      setIsSubmitting(false);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      {error && <div className="error-alert">{error}</div>}
      
      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? CE9178">'Saving...' : CE9178">'Save Changes'}
      </button>
    </form>
  );
};

Notice the use of the finally block. This is critical: regardless of whether the request succeeded or failed, we must reset isSubmitting to false to restore the UI for the next attempt.

Hands-on Exercise

Integrate this pattern into your current dashboard project:

  1. Locate your user settings or profile update form.
  2. Add an isSubmitting state initialized to false.
  3. Wrap your API call in a try/catch/finally block.
  4. Disable the "Save" button while isSubmitting is true.
  5. Display an error message if the catch block executes.

Common Pitfalls

  • Forgetting the finally block: If your API call hangs or fails, the user is left with a disabled button forever, forcing a page refresh. Always include finally.
  • Ignoring the type="submit" attribute: Always define the button type. Without it, some browsers default to submit, but explicitly setting it makes your code intent clear.
  • Over-relying on global state: Don't move isSubmitting to a global context if it's only needed for one form. Keep it local to the component to avoid unnecessary re-renders of the entire app.
  • Ignoring Race Conditions: If you use useEffect to trigger submissions based on state changes instead of explicit event handlers, you risk multiple triggers. Stick to button-driven events.

Recap

Optimizing form submissions is about communication and control. By disabling buttons, we prevent accidental duplicate submissions; by utilizing try/catch/finally, we ensure our application stays responsive even when the server fails. These small details transform a functional form into a production-grade component.

Up next: We will use the React Profiler to identify performance bottlenecks and ensure these components remain snappy as our application scales.

Previous lessonHandling Multi-step FormsNext lesson Performance Profiling with React DevTools
Back to Blog

Similar Posts

ReactJune 26, 20263 min read

Handling Multi-step Forms: Building Robust Wizards in React

Master multi-step forms by centralizing state and managing wizard navigation. Learn to persist data across steps for a seamless dashboard configuration UX.

Read more
ReactJune 25, 20264 min read

Controlled Components: Managing Form Input State in React

Master controlled components in React by binding input values to state. Learn to handle multiple form fields and reset state after submission with ease.

Part of the course

Intermediate React: Hooks, State & Data Patterns

intermediate · Lesson 32 of 48

  1. 1

    Mastering useRef for DOM Access

    4 min
  2. 2

    Persistent Mutable Values with useRef

    4 min
  3. 3

    Memoizing Expensive Calculations with useMemo

    3 min
Read more
ReactJune 26, 20264 min read

Deploying the Application: From Local Build to Production

Master the production build process for your React dashboard. Learn to handle environment variables, optimize assets, and deploy securely to the web.

Read more
4

Optimizing Function References with useCallback

3 min
  • 5

    Introduction to Custom Hooks

    4 min
  • 6

    Building a useLocalStorage Hook

    4 min
  • 7

    Refactoring Dashboard Settings

    4 min
  • 8

    Complex State with useReducer

    3 min
  • 9

    Managing Object-Based State

    3 min
  • 10

    Introduction to Context API

    3 min
  • 11

    Architecting Global State with Context and Reducer

    3 min
  • 12

    Implementing Theme Context

    4 min
  • 13

    Structuring State for Performance

    3 min
  • 14

    Handling Authentication State

    3 min
  • 15

    Integrating Reducers with Auth State

    3 min
  • 16

    Introduction to React Router

    3 min
  • 17

    Dynamic Routing with URL Parameters

    3 min
  • 18

    Nested Routes and Layouts

    4 min
  • 19

    Protected Routes for Authenticated Views

    3 min
  • 20

    Programmatic Navigation

    3 min
  • 21

    Building the Dashboard Navigation Structure

    3 min
  • 22

    Asynchronous Data Lifecycle

    3 min
  • 23

    Caching Strategies with React Query

    4 min
  • 24

    Mutations and Data Updates

    4 min
  • 25

    Synchronizing Client and Server State

    3 min
  • 26

    Integrating Live Data into the Dashboard

    3 min
  • 27

    Error Handling and Loading UI

    3 min
  • 28

    Controlled vs Uncontrolled Components

    3 min
  • 29

    Real-time Form Validation

    3 min
  • 30

    Schema-based Validation with Zod

    3 min
  • 31

    Handling Multi-step Forms

    3 min
  • 32

    Optimizing Form Submissions

    3 min
  • 33

    Performance Profiling with React DevTools

    3 min
  • 34

    Refactoring for Scalability

    3 min
  • 35

    Finalizing Dashboard Data Flow

    3 min
  • 36

    Deploying the Application

    4 min
  • 37

    Advanced Hook Composition

    3 min
  • 38

    Implementing Middleware for State

    Coming soon
  • 39

    Advanced Context Patterns

    Coming soon
  • 40

    Router Loaders and Data Prefetching

    Coming soon
  • 41

    Complex Route Guards

    Coming soon
  • 42

    Handling Large Datasets in UI

    Coming soon
  • 43

    Testing Hooks and Components

    Coming soon
  • 44

    Managing Global Modals

    Coming soon
  • 45

    Implementing Keyboard Shortcuts

    Coming soon
  • 46

    Optimizing Asset Loading

    Coming soon
  • 47

    Internationalization Basics

    Coming soon
  • 48

    Managing WebSocket Connections

    Coming soon
  • View full course