Introduction to Managing the Form State

Learn how to create a React form with controlled components and manage the values of the form fields in the component's state.

Setup

This course allows you to code along so that it’s easier to get a good grasp of the concepts you’ll be learning. You can code directly in this browser by editing and running the code widgets on this platform.

Create the form interface

Let’s create the markup for our form and give it some CSS styles.

import React from 'react';
import './style.css';

import ReactDOM from 'react-dom';
import App from './app.js';

ReactDOM.render(
  <App />, 
  document.getElementById('root')
);
A simple form interface with React

The code snippet above is the markup and style for a form’s interface. We won’t need to go into details.

Currently, the fields in this form are uncontrolled components because they manage their own states, and no field is aware of the state of another field. So to get the input data from any of the fields, we need to create event listeners. However, we won’t be doing that in this lesson.

Next, we’ll create component-level states that the input fields will get their data from.

Manage the form state

We make use of the useState hook to manage the state in React functional components. The syntax is as follows:

Press + to interact
const [name, setName] = useState("");

This creates a state variable, name, which is accessible throughout the component, and a setName function that can be used to update the value of name. The setName function is also accessible throughout the component.

Let’s update our app.js file.

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}
Controlled component

From line 4 to line 9, we create a state to manage the values of our input fields. The values object contains four keys: name, email, phone, and password. We also have a setValues function that we’ll use to update any or all of the keys in values.

From line 11 to line 16, we create a handleChange function. This function uses the setValues function to update the value of the values object in the state.

Let’s take a closer look at the content of the function.

Press + to interact
const handleChange = (e) => {
setValues({
...values,
[e.target.name]: e.target.value,
});
};

This expression updates the value of event.target.name (the name of the field that was changed) to e.target.value (the current value of the field).

For each input field, we make them get their values from the state, and we indicate an onChange event that calls the handleChange function. This means that whenever the value of an input field is changed, it calls the handleChange function with an argument event, which is the onChange event. The handleChange function uses this event object to know which field has called it. It then gets the name of the field that we have specified and updates its value in the state with the field’s value after the change.

Note: We use the names of these input fields as the keys of our values state. This makes it easier to track.

From line 66 to line 79, we write markup that displays the values of values.name, values.email, values.phone, and values.password.

When we type into any of the input fields, we see that whatever we type gets displayed in the corresponding section where the values of our state for that field are displayed.

This shows us a number of things.

  • The values of a component state can be accessed from anywhere in the component.
  • When we allow our form to get its data from the component-level state, we have access to whatever is inputted into the form as soon as it gets inputted. This opens many possibilities, which are listed below:
    • Our forms are immediately validated.
    • Our form fields must perform actions based on the input of another field. A common example is when we have two select drop-downs in a form. The first drop-down enables us to select a country, and the second allows us to select a region in the selected country. The drop-down that displays the list of regions must include a selected country, so it provides the possible regions from that country.

Summary

Let’s highlight the steps we took to create a controlled form component, which has its data managed in the component’s state.

  • We created the interface for our form.
  • We created an object in the state using the useState hook. This gave us access to an identifier we used to get the value of the state and a function to modify the state.
  • We created a handleChange event that used the state-modifying function to update the value of a key in a state.
  • We allow all input fields to get their values from the state.
  • We listened to the onChange event of each input field and called this handleChange function when the event was fired so it updates the state with the new input value.

Since we have access to the form data at all times, this can help us validate the values provided in the form before sending our data to the API or other components.