Course: Section

Get Started with Modern React: Step by Step

Episode: Title

S02・V16: Forms (Part 1)

Date Created: July 17th, 2019
Last Updated: 27 days ago

Objectives
  1. We will show you how an HTML form works.
  2. We will implement a form in React as a controlled component.
Watch Video
Duration: 6m 22s

HTML Forms

HTML form elements work a little bit differently from other DOM elements in React, because form elements naturally keep some internal state.

Let’s remind ourselves how a form works in HTML. To start, let’s go to the index.html file in the public/ folder.

public/index.html
<!DOCTYPE html>
<html lang="en">

  <head>
    <title>React App</title>
  </head>

  <body>
    <div id="root"></div>
  </body>

</html>

We will add the HTML form above the root div. Now, we will add a label of “Name:”. And also a text input for the name. Finally, we will add a submit input button.

public/index.html
<!DOCTYPE html>
<html lang="en">

  <head>
    <title>React App</title>
  </head>

  <body>
    <form>      <label>        Name:        <input type="text" name="name" />      </label>      <input type="submit" value="Submit" />    </form>
    <div id="root"></div>
  </body>

</html>

This form has the default HTML form behavior of browsing to a new page when the user submits the form. Let’s remove this HTML form, before implementing it in React.

React Form

Return to src/index.js. We will implement exactly the same form in React.

src/index.js
import React from "react";
import ReactDOM from "react-dom";

ReactDOM.render(
  <form>    <label>      Name:      <input type="text" name="name" />    </label>    <input type="submit" value="Submit" />  </form>,  document.getElementById("root")
);

If you want this behavior in React, it just works.

Controlled Components

In most cases, it’s convenient to have a JavaScript function that handles the submission of the form and has access to the data that the user entered into the form. The standard way to achieve this is with a technique called “controlled components”.

In HTML, form elements such as input, textarea, and select, typically maintain their own state, and they update state based on user input. In React, mutable state is typically kept as component state. We can make React’s state the “single source of truth”. Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a “controlled component”.

For example, if we want to make the previous example log the name when it is submitted, we can write the form as a controlled component. We will call the component NameForm.

src/index.js
import React from "react";
import ReactDOM from "react-dom";

ReactDOM.render(
  <NameForm />,
  document.getElementById("root")
);

Now, we will define the NameForm component. We will hold the form value in state, and give it an initial empty string. We will need to import the useState hook. We will define a handler to deal with any changes in the form, which we can get from the event target’s value, and use it to set the value in state. We will also define a handler to deal with form submission. We will create an alert. And, we will prevent the default behavior of the browser, which is to reload the page on submission.

Then, return the form, with an onSubmit prop to which we pass the handleSubmit handler. Add the name label. Then, add the text input with the controlled value, and the onChange prop, to which we will pass the handleChange handler. Finally, add the form submit input button.

src/index.js
import React, { useState } from "react";
import ReactDOM from "react-dom";

const NameForm = () => {
  const [value, setValue] = useState("");

  const handleChange = event => {
    setValue(event.target.value);
  };

  const handleSubmit = event => {
    alert(`A name was submitted: ${value}`);
    event.preventDefault();
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        <input type="text" value={value} onChange={handleChange} />
      </label>
      <input type="submit" value="Submit" />
    </form>
  );
};

ReactDOM.render(
  <NameForm />,
  document.getElementById("root")
);

Since the value attribute is set on our form element, the displayed value will always be the state variable value, making the React state the source of truth. Since handleChange runs on every keystroke to update the React state, the displayed value will update as the user types. With a controlled component, every state update will have an associated handler function. This makes it straightforward to modify or validate user input.

For example, if we wanted to enforce that names are written with all uppercase letters, we could write handleChange to accommodate that.

  const handleChange = event => {
    setValue(event.target.value.toUpperCase());  };

Anything we now input is in uppercase.

Summary

We showed you how an HTML form works, and we implemented a form in React as a controlled component.

Next Up…

In the next video, we will continue to cover forms in React.