React Forms Basics

ReactBeginner
Practice Now

Introduction

In web development, forms are essential for collecting user input. In React, handling form data is a bit different from traditional HTML. The recommended approach is to use a technique called "controlled components."

With controlled components, the form's data is handled by the React component's state. This makes the React state the "single source of truth," allowing you to manage, validate, and respond to user input in a predictable way.

In this lab, you will build a simple form with a single text input and a submit button. You will learn how to:

  • Create form elements in JSX.
  • Use the useState hook to manage the input's value.
  • Handle user input with the onChange event.
  • Process form submissions with the onSubmit event.

By the end of this lab, you will have a solid understanding of the fundamentals of React forms.

This is a Guided Lab, which provides step-by-step instructions to help you learn and practice. Follow the instructions carefully to complete each step and gain hands-on experience. Historical data shows that this is a beginner level lab with a 100% completion rate. It has received a 100% positive review rate from learners.

Create input element with onChange attribute

In this step, you will start by creating the basic structure of our form. This includes adding a form element and a text input field. We will also add the onChange attribute, which is crucial for tracking changes to the input's value.

First, let's get our development environment ready. We need to install the project dependencies and start the development server.

Open a terminal in the WebIDE and run the following commands, one by one. Make sure you are in the ~/project/my-app directory.

cd my-app
npm install

This command installs all the necessary packages defined in package.json.

Now, start the development server:

npm run dev -- --host 0.0.0.0 --port 8080

Next, navigate to the my-app/src directory in the file explorer on the left and open the App.jsx file. We will modify this file to add our form.

Replace the content of App.jsx with the following code. We are adding a <form> tag and an <input> element inside it. The onChange attribute is added to the input, which will later be used to handle value changes.

import "./App.css";

function App() {
  return (
    <form>
      <h1>React Form</h1>
      <label>
        Enter your name:
        <input type="text" onChange={() => {}} />
      </label>
    </form>
  );
}

export default App;

After saving the file, switch to the Web 8080 tab in the LabEx interface. You should see a simple form with a text input field. If you don't see the changes, try refreshing the tab. At this point, typing in the input field won't do anything, but we have the basic structure in place.

Simple form with text input and label

Handle change with function updating state

In this step, you will make the input field interactive. To do this, we need to store its value in the component's state. We will use the useState hook to create a state variable and a function to update it.

First, we need to import the useState hook from the 'react' library. Then, we'll declare a state variable, let's call it name, to hold the value of the input.

Next, we'll create a function called handleChange. This function will be triggered every time the user types in the input field. Inside this function, we'll use the setName function provided by useState to update our name state with the input's current value, which we can access via event.target.value.

Update your App.jsx file with the following code:

import { useState } from "react";
import "./App.css";

function App() {
  // Create a state variable 'name' and a function 'setName' to update it
  const [name, setName] = useState("");

  // Define the event handler function
  const handleChange = (event) => {
    setName(event.target.value);
  };

  return (
    <form>
      <h1>React Form</h1>
      <label>
        Enter your name:
        {/* Connect the handler to the onChange event */}
        <input type="text" onChange={handleChange} />
      </label>
    </form>
  );
}

export default App;

Now, when you type in the input field, the handleChange function is called, and the name state is updated on every keystroke. Although you can't see the change on the screen yet, the component's state is now tracking the input's value. This is the first half of creating a controlled component.

Set input value attribute to state value

In this step, we will complete the "controlled component" pattern. A controlled component is one where the input's value is driven by the React state, making the state the "single source of truth."

To achieve this, we need to bind the value attribute of the <input> element directly to our name state variable. This creates a two-way data binding:

  1. The user types, triggering onChange, which updates the state.
  2. The state update causes a re-render, and the input's value is set to the new state value.

This ensures that the UI is always in sync with the component's state.

Modify the <input> element in your App.jsx file to add the value attribute, like this:

import { useState } from "react";
import "./App.css";

function App() {
  const [name, setName] = useState("");

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

  return (
    <form>
      <h1>React Form</h1>
      <label>
        Enter your name:
        {/* Bind the input's value to the state */}
        <input type="text" value={name} onChange={handleChange} />
      </label>
    </form>
  );
}

export default App;

After saving the file, go back to the Web 8080 tab. The form will look the same, but it is now a fully controlled component. The input field's display is now directly controlled by the name state variable in your React component.

Add submit button with onClick handler

A form isn't complete without a way to submit it. In this step, you will add a submit button and an event handler to process the form submission.

The standard and most accessible way to handle form submissions in React is by using the onSubmit event on the <form> element itself. This ensures that the form can be submitted by clicking the button or by pressing the "Enter" key in an input field.

First, let's add a <button> with type="submit" inside our form. Then, we'll create a new handler function, handleSubmit, and attach it to the <form> element's onSubmit attribute.

Update your App.jsx file with the following code:

import { useState } from "react";
import "./App.css";

function App() {
  const [name, setName] = useState("");

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

  // Create the submit handler function
  const handleSubmit = (event) => {
    // We will add more logic here in the next step
    console.log("Form was submitted");
  };

  return (
    // Attach the handler to the form's onSubmit event
    <form onSubmit={handleSubmit}>
      <h1>React Form</h1>
      <label>
        Enter your name:
        <input type="text" value={name} onChange={handleChange} />
      </label>
      {/* Add a submit button */}
      <button type="submit">Submit</button>
    </form>
  );
}

export default App;

Now, if you go to the Web 8080 tab, you will see a "Submit" button. If you click it, you might notice the page quickly reloads. This is the default browser behavior for form submission, which we will address in the final step.

Prevent submit default and log form data

In this final step, you will complete the form's functionality. As you noticed, clicking the submit button causes a full page reload. In a Single-Page Application (SPA) like one built with React, we want to handle form submissions using JavaScript without reloading the page.

To do this, we need to call event.preventDefault() inside our handleSubmit function. The event object is automatically passed to the event handler, and this method stops the browser's default action.

Once we've prevented the default behavior, we can access the submitted data from our state and do something with it, like showing an alert to the user.

Let's update the handleSubmit function in App.jsx to implement this logic.

import { useState } from "react";
import "./App.css";

function App() {
  const [name, setName] = useState("");

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

  const handleSubmit = (event) => {
    // Prevent the default form submission behavior
    event.preventDefault();
    // Show an alert with the submitted name
    alert(`A name was submitted: ${name}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <h1>React Form</h1>
      <label>
        Enter your name:
        <input type="text" value={name} onChange={handleChange} />
      </label>
      <button type="submit">Submit</button>
    </form>
  );
}

export default App;

Save the file. Now, go to the Web 8080 tab, type a name into the input field, and click the "Submit" button. You should see an alert pop up with the name you entered, and the page will not reload.

Congratulations! You have successfully built a basic controlled form in React.

Summary

In this lab, you learned the fundamental principles of handling forms in React using the "controlled components" pattern.

You have successfully:

  • Created a form with an input field and a submit button using JSX.
  • Used the useState hook to manage the form's data within the component's state.
  • Implemented an onChange event handler to update the state as the user types, keeping the UI and state in sync.
  • Handled the form submission with an onSubmit event handler, preventing the browser's default page reload by using event.preventDefault().
  • Accessed the form data from the state upon submission.

These concepts are the building blocks for creating more complex and interactive forms in your React applications. You can now apply this knowledge to build forms with multiple inputs, different input types, and validation logic.