Forms are an essential part of any frontend app — and with React, they can be either simple or a real nightmare. In this article, you’ll learn 3 common traps when handling forms in React — and how to avoid them with practical examples.
🪤 1. Updating state on every onChange
(and re-rendering too much)
A common mistake is using useState
for every field and updating them on every change. This leads to unnecessary re-renders and messy code.
❌ Trap: Excessive useState
function ContactForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [message, setMessage] = useState('');
return (
<form>
<input value={name} onChange={e => setName(e.target.value)} />
<input value={email} onChange={e => setEmail(e.target.value)} />
<textarea value={message} onChange={e => setMessage(e.target.value)} />
</form>
);
}
✅ Better: use useRef
to avoid re-renders
import { useRef } from "react";
function ContactForm() {
const nameRef = useRef();
const emailRef = useRef();
const messageRef = useRef();
function handleSubmit(e) {
e.preventDefault();
const name = nameRef.current.value;
const email = emailRef.current.value;
const message = messageRef.current.value;
console.log({ name, email, message });
}
return (
<form onSubmit={handleSubmit}>
<input name="name" ref={nameRef} />
<input name="email" ref={emailRef} />
<textarea name="message" ref={messageRef} />
<button type="submit">Send</button>
</form>
);
}
🪤 2. Not validating data before submission
Another mistake is sending data without checking validity first - this causes failed requests and user frustration.
❌ No validation:
<form onSubmit={handleSubmit}>
<input name="email" value={form.email} onChange={handleChange} />
<button type="submit">Submit</button>
</form>
✅ Basic validation example:
function handleSubmit(e) {
e.preventDefault();
if (!form.email.includes('@')) {
alert('Invalid email!');
return;
}
// send data here...
}
🪤 3. Building complex forms without libraries
Manually handling large, validated forms can quickly become unmanageable. Use libraries like React Hook Form or Formik.
✅ Example with React Hook Form:
import { useForm } from "react-hook-form";
function NewsletterForm() {
const { register, handleSubmit, formState: { errors } } = useForm();
function onSubmit(data) {
console.log(data);
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("email", { required: true })} placeholder="Email" />
{errors.email && <span>Email is required</span>}
<button type="submit">Subscribe</button>
</form>
);
}
✅ Conclusion
Avoiding these 3 traps will already put you ahead of many React developers:
- Manage form state smartly - or avoid state when possible with
useRef
. - Always validate user input before submitting.
- Don’t reinvent the wheel - use good libraries.
💬 Enjoyed it? Drop a comment or share your own form horror story!
🔗 Follow me at dev.to/werliton for more hands-on React content.
Top comments (6)
Pretty cool breakdown, honestly forms always trip me up- guessing long-term, using good tools saves so much pain.
Yeah. they always save us
React Hook Form honestly changed how I handle bigger forms, it just makes life easier.
What's been your worst React form bug so far?
Man, I would say use usestate for every field in a form with more than 20 fields. Sad. Since I don't even need to display the value on the screen, just capture it. That's what motivated this post.
Niceeee
thanks