Part 110: Enhancing Form Submission in Next.js: Error Handling and Preventing Duplicates
[App] Server Actions

Handling form submissions effectively is a crucial aspect of web development. It ensures that users have a smooth experience and that data integrity is maintained. In this post, we'll discuss how to handle server-side validation errors and prevent duplicate submissions in a Next.js application. We'll also explore how to visually communicate submission states to users.
Error Handling: Displaying Validation Messages
Before diving into preventing duplicate submissions, let's review how we handle errors returned by the server. When a form submission fails due to server-side validation, it's essential to display a meaningful error message to the user. Here's how we achieve that using a state variable to manage errors.
Simulating a slow internet connection, such as Slow 3G, in Chrome is a useful way to test how your web application performs under different network conditions. Here’s how you can set it up using Chrome DevTools:
Open Chrome DevTools:
Right-click anywhere on the webpage and select "Inspect" from the context menu.
Alternatively, you can use the keyboard shortcut
Ctrl + Shift + Ion Windows/Linux orCmd + Option + Ion macOS.
Navigate to the Network Tab:
In the DevTools panel, click on the "Network" tab. This tab allows you to monitor network requests and simulate different network conditions.
Access Throttling Options:
At the top of the Network tab, you’ll see a dropdown labeled "No throttling" by default.
Click on this dropdown to see a list of predefined network conditions.
Select Slow 3G:
From the dropdown menu, select "Slow 3G". This will simulate a slow 3G network connection, which has limited bandwidth and higher latency.
Test Your Application:
With Slow 3G enabled, interact with your web application to see how it behaves under slower network conditions.
This is particularly useful for testing form submissions, image loading, and overall page performance.
Return to Normal Network Conditions:
Once you’ve finished testing, you can return to normal network speed by selecting "No throttling" from the same dropdown menu.
By simulating a slow internet connection, you can identify performance bottlenecks and improve the user experience for users with limited bandwidth. This testing method is crucial for ensuring that your application is accessible and performs well for all users, regardless of their network speed.
Code Implementation
Here's a simplified version of the code that manages error states and displays error messages:
// components/CommentForm.jsx
'use client';
import { useState } from 'react';
import { createCommentAction } from '@/app/reviews/[slug]/actions';
export default function CommentForm({ slug, title }) {
const [state, setState] = useState({ loading: false, error: null });
const handleSubmit = async (event) => {
event.preventDefault();
setState({ loading: true, error: null });
const form = event.currentTarget;
const formData = new FormData(form);
const result = await createCommentAction(formData);
if (result?.isError) {
setState({ loading: false, error: result });
} else {
form.reset();
setState({ loading: false, error: null });
}
};
return (
<form onSubmit={handleSubmit}
className="border bg-white flex flex-col gap-2 mt-3 px-3 py-3 rounded">
<p className="pb-1">
Already played <strong>{title}</strong>? Have your say!
</p>
<input type="hidden" name="slug" value={slug} />
<div className="flex">
<label htmlFor="userField" className="shrink-0 w-32">
Your name
</label>
<input id="userField" name="user"
className="border px-2 py-1 rounded w-48"
/>
</div>
<div className="flex">
<label htmlFor="messageField" className="shrink-0 w-32">
Your comment
</label>
<textarea id="messageField" name="message"
className="border px-2 py-1 rounded w-full"
/>
</div>
{Boolean(state.error) && (
<p className="text-red-700">{state.error.message}</p>
)}
<button type="submit" disabled={state.loading}
className="bg-orange-800 rounded px-2 py-1 self-center
text-slate-50 w-32 hover:bg-orange-700
disabled:bg-slate-500 disabled:cursor-not-allowed">
Submit
</button>
</form>
);
}Preventing Duplicate Submissions
Duplicate submissions can occur when users click the submit button multiple times, especially on slow internet connections. To prevent this, we can disable the submit button while a request is in progress. This gives users visual feedback that their request is being processed and prevents multiple submissions of the same form data.
How It Works
State Management: We use a single state variable,
state, to manage both the loading and error states. This helps us track whether a form submission is in progress.Disable Button: The submit button is disabled when
state.loadingistrue. This prevents users from clicking the button multiple times while a request is being processed.Visual Feedback: We apply styles to the disabled button using Tailwind CSS classes. The button's background color changes to a "slate" gray, and the cursor changes to indicate that clicking is not allowed.
CSS Classes
Using Tailwind CSS, we can easily apply styles to the disabled button:
disabled:bg-slate-500: Changes the background color of the button when it's disabled.disabled:cursor-not-allowed: Changes the cursor to indicate that the button is not clickable.
Testing the Solution
To ensure that our implementation works as expected, we can simulate a slow internet connection using browser DevTools. This gives us more time to test the button's behavior when clicked multiple times. After the first click, the button should become disabled, preventing further submissions.
Conclusion
By managing error states and preventing duplicate submissions, we enhance both the usability and reliability of our forms in Next.js applications. Users receive immediate feedback if there's a validation error, and they are prevented from submitting the same data multiple times. For a more polished user interface, consider adding a loading spinner to indicate that a request is in progress. This approach ensures a smooth and effective user experience while maintaining data integrity.
Last updated