React Forms
Forms both in React and in other programming languages are one of the most often used attributes that can either bring to better user experience or dissatisfaction whenever the data cannot be submitted. Either you want to sign in or sign up, they are the essentials part of most web applications. But let’s stay positive and build a form that will not eventually break and will work seamlessly, the way it’s supposed to. For this reason, we’ll build React-based and backed forms that are relatively easy to build and require full implementation of one of the main React properties called state
while, as you might know, state
are the data that intrinsic to the component and can dynamically change on every interaction. We will also cover in this article two most used events such as onChange
and onClick
.
As an instance, we can cover the registration form, one of the most used forms out there. In general, what commonalities all the registration forms have? First of all, there are input fields where the user types something (usually, name, email, and that kind of stuff). Then, when user types, React somehow understands, reacts, and stores that specific data. After that, we click the submit button. When that happens, it triggers a “two-sided conversation” before front and back ends, where we send that specific data that the user typed in. Back-end either responses with 200 status (ok), or shoots an error if the data is invalid, the specified path is inaccurate, etc. First things first, let’s start with a single form that doesn’t do much (except looking cool) and add some functionality and complexity as it evolves.
import React, { Component } from 'react';export default class Registration extends Component {
render() {
return (
<>
<form className="form-control">
<input type="text" name="name"/>
<input type="email" name="email" required/>
<input type="password" name="password"/>
<button type="submit">Register</button>
</form>
</>
)
}
}
This is a classical form written by JSX. We have a form opening and closing tags, input fields with different types, submit button (which doesn’t do anything right now). This is what the user sees and instinctively tries to submit the filled data. Let’s help the user to have the best experience by adding some functionality! First of all, we have to deal with state
while as you know, state
are responsible for dynamic data, such as forms, increment, etc.
export default class Registration extends Component {
state = {
name: "",
email: "",
password: "",
}
}
As you notice, state
is an object with key-value pairs, where the keys should exactly match with name
parameter of the form. For instance, if in the form we have name=”password”
, then in state
we must have the matching password
key. Another thing to mention here is that value
represents the initial value, in our case an empty string to start with (or 0 if dealing with a counter). That’s good, but how do we connect them together and change the state
? Don’t be hasty, Smeagol! We can all agree that whenever we type, we want the input fields to change, so, let’s change it programmatically by writing onChange
eventListener
!
export default class Registration extends Component { state = {
name: "",
email: "",
password: "",
} handeChange = event => {
const {name, value} = event.target;
this.setState({[name]: value})
}render() {
return (
<>
<form className="form-control">
<input type="text" name="name" value={this.state.name}
onChange={this.handeChange}/>
<input type="email" name="email" value={this.state.email}
onChange={this.handeChange} required/>
<input type="password" name="password" value={this.state.password}
onChange={this.handeChange}/>
<button type="submit">Register</button>
</form>
</>
)
}
}
Let’s take a moment and look at what just was added and how it will now function. First of all, the value
attribute in the input field appeared. value={this.state.email}
represents what in the current moment the value of state
. onChange
is responsible for every keystroke we type in the field. So, whenever we do so, we want to run a particular function conventionally named handleChange
. We access this function bythis
keyword. Thus, we have onChange={this.handleChange}
. As we look just above our form we’ll notice the handleChange
function. In this simple yet powerful function, first, we designate the roles by creating variables (const name = event.target.name
, const value = event.target.value
, or simply and nicely restructuring them as const { name, value }= event.target
so we can type shorter syntax afterward). A line below is where all the magic happens when we invoke another React-specific method called this.setState
. If the state
is initial value, setState
is what we want this value to become. It returns an object when we event.target.name
to event.target.value
(or simply [name]: value
). For instance, if initially name=”email”
represents an empty string, we now set that name
to whatever the value
we typed in by implementing setState
method.
So by far, we have done a lot of work but there is one more step that need to be done for our form to be fully capable of managing data. We need to submit these values to the back-end. We can do it by using onSubmit
eventListener
and handleSubmit
method.
...
<form className="form-control" onSubmit={this.handleSubmit}>
...
Just a few lines above we can write our method required for all the forms whenever we need to send and get back data from the server-side.
...
handleSubmit = event => {
const {name, email, password} = this.state
event.preventDefault();
fetch("http://localhost:3000/registration", {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
method: 'POST',
body: JSON.stringify({name, email, password})
})
.then(resp => resp.json())
.then(data => this.setState({name: data.name, email: data.email, password: data.password}))
.catch(err => console.log(err))
}<form className="form-control" onSubmit={this.handleSubmit}>
...
Without explicitly describing fetch
method, we can see what it actually does. We specify the address of the server-side where the data must be sent, we say to the server that this data type is json
. We explicitly what type of HTTP request it is (POST
), we convert the json
data to a string by using JSON.stringify
method. Then we receive a promise that some type of data will be sent back, then we receive the data itself and update our state
according to the received data by using setState
method.
Conclusion
Forms are a great example to see the power of React in action. They represent one of the most common experiences the user encounters throughout the webpages. After spending some time required for initial setup and elaborating every detail, React forms start to perform all the magic and seamless communication with the back-end where we can decide what to do with the received data, how to update state on the front-end, persist the data in the server-side database, or not. But that’s a story for another article.