DEV Community

Abhishek Agrawal
Abhishek Agrawal

Posted on • Edited on • Originally published at fazer1929.github.io

Handling Forms in ReactJS the right way

Hello everyone, recently I came across a new way to handle React forms, maybe its something you know, maybe you've been doing this for years and think I am an Idiot for not knowing this earlier, but it is what it is so let's go.

Using react forms the old way

Let's consider a simple signup form that contains only 3 fields namely username, email, and password. Here's how I used to use forms earlier.

import React,{useState} from 'react';
const SignUp = () => {
    const [username,setUsername] = useState("");
    const [password,setPassword] = useState("");
    const [email,setEmail] = useState("");

    const handleEmailChange(e){
        setEmail(e.target.value);
    }
    const handlePasswordChange(e){
        setPassword(e.target.value);
    }
    const handleUsernameChange(e){
        setUsername(e.target.value);
    }
    return(
        <form>
            <input type="text" placeholder="username" onChange={handleUsernameChange} value={username}/>
            <input type="email" placeholder="email" onChange={handleEmailChange} value={email}/>
            <input type="password" placeholder="password" onChange={handlePasswordChange} value={password}/>
            <input type="submit" value="Submit"/>
        </form>
    );
}
Enter fullscreen mode Exit fullscreen mode

Maybe you think wtf is this guy and why is the code is so bad. There's only one thing I can say to you, sorry. To the other people who think there's nothing wrong with the code, prepare to get your mind blown.

Let's look at the problems with the code first-

  1. Its a lot of state variables for handling a form, especially if you think about bigger forms with 10s of fields.
  2. The handleChange functions are totally redundant and can be easily refactored.

So, now let's look at the amazing code to handle forms -

import React,{useState} from 'react';
const SignUp = () => {
const [formData, setFormData] = useState({
    username: "",
    email: "",
    password: "",
});

    const handleChange=(e)=>{
        const newFormData = {
            ...formData,
            [e.target.name]:e.target.value
        };
        setFormData(newFormData);
    }

    return(
        <form>
            <input type="text" name="username" placeholder="username" onChange={handleChange} value={username}/>
            <input type="email" name="email" placeholder="email" onChange={handleChange} value={email}/>
            <input type="password"  name="password" placeholder="password" onChange={handleChange} value={password}/>
            <input type="submit" value="Submit"/>
        </form>
    );
}
Enter fullscreen mode Exit fullscreen mode

Beautiful code, Right? Well, when I found it I thought it was amazing and worth sharing.
But before you leave, make sure that the formData's keys are same as the input's name, else you're code won't work properly.


That's pretty much it.
Thank you for reading. Bye

Top comments (13)

Collapse
 
dikamilo profile image
dikamilo • Edited

Is better to use prevState argument when chaning state based of previous state because setState is asynchronous and may cause unstable updates.

setFormData((prevState) => {
    return {
        ...prevState,
        [e.target.name]: e.target.value
    }
});
Enter fullscreen mode Exit fullscreen mode

or in more short form:

const handleChange = event => 
    setFormData(prevState => 
        ({ ...prevState, [event.target.name]: event.target.value })
    );
Enter fullscreen mode Exit fullscreen mode
Collapse
 
fazer1929 profile image
Abhishek Agrawal

Thank you for the suggestion.

Collapse
 
moinax profile image
Jérôme Poskin • Edited

In the second example you forgot to rename your handlers to handleChange. This could be confusing for newbies.
Anyway it's a good start, but as some others told you, you should rely on form libraries. I tested a lot of them and I kind of like final-form for building big forms and reusable fields, then I would recommend you Yup for the validation. The latter is working pretty well with any form library by the way.

Collapse
 
dikamilo profile image
dikamilo

Formik + Yup is very good combo.

Collapse
 
moinax profile image
Jérôme Poskin

Yes I used Formik before but got issues with null values and complex forms. I didn't encountered any of those issues with final-form which I'm using in production for a year now

Collapse
 
fazer1929 profile image
Abhishek Agrawal

Thanks for pointing it out, I've updated it.
I totally agree that third party libraries are excellent way of handling React forms.
I just found about this way and thought it was pretty neat.

Collapse
 
evanwinter profile image
Evan Winter

Nice – a couple things I had to tweak to get working, though:

  • <input /> elements need names like name="username", otherwise the change handler doesn't know which state value to update
  • const handleChange(e){} needs to either be const handleChange = (e) => {} or function handleChange(e){}
Collapse
 
fazer1929 profile image
Abhishek Agrawal

Thanks for pointing it out

Collapse
 
chrischism8063 profile image
chrischism8063

I agree this is a good writeup!!

I'd also suggest adding a validation layer.

I know you want to keep this as a simple example but that is also something basic to always add when working on forms.

Between required fields to ensuring the dat isn't being submitted with empty strings.

Many things could be added in the validation layer

Collapse
 
yasamoka profile image
Ramzi Sabra

This is a solved problem already. React Hook Form, Formik, React Final Form, etc... are solid libraries.

Collapse
 
dariorlima profile image
Dário Ribeiro • Edited

This trick is very nice! Thanks for sharing.

Collapse
 
fazer1929 profile image
Abhishek Agrawal

You're welcome. Thanks for reading

Collapse
 
nnhjs profile image
Hung Nguyen

Fun fact: *This is recommended of reactjs.org
Read more here: reactjs.org/docs/forms.html#handli...