Skip to content

time2fishman/react-forms

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

General Assembly Logo

React Forms

Forms to allow users to interact with our web application. In HTML forms can have some unexpected behaviors for new developers.

Learning Objectives

  • Describe how HTML forms work.
  • Use buttons inside HTML forms.
  • Build forms utilizing accessibility best practices.
  • Distinguish between controlled and uncontrolled form elements in React.

HTML Form Element

In HTML, the <form></form> element represents a document section containing interactive controls for submitting information.

  • Any button without a type attribute, or any button or input element with the an attribute of type="submit" will cause a submit event to be fired.
  • By default, when forms are submitted they will cause the page to reload in HTML.
  • In order to prevent the page from reloading, you should listen for the submit event using JavaScript and make sure to call the preventDefault method on the event.

HTML Form Elements

Form elements include various types of interactive elements, such as text fields, checkboxes, radio buttons, checkboxes, select elements and many more. There are also a variety of type attributes for the <input/> element that can change the behavior of the input as well as restrict the type of data that can be entered.

It is particularly important to pay attention to accessibility best practices when creating forms in HTML.

<form>
  <!-- Connect every field to a label using the `for` attribute -->
  <!-- The `id` of the input uniquely connects the label and input -->
  <label for="email">Email:</label>
  <input id="email" type="email" />
  <label for="password">Password:</label>
  <input id="password" type="password" />
</form>

Forms in React

By their nature, forms are stateful. They need to remember information that will be submitted to the server for processing. There is a pattern that we use for this in React. You can use this same pattern for all form processing in React!

import React, { useState } from 'react';

function LoginForm() {
  const initialState = { username: '', password: '' };
  const [formState, setFormState] = useState(initialState);

  const handleChange = (event) => {
    setFormState({ ...formState, [event.target.id]: event.target.value });
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    // do something with the data in the component state
    console.log(formState);
    // clear the form
    setFormState(initialState);
  };
  // Note that we need to use `htmlFor` instead of `for` in JSX
  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="username">Username:</label>
      <input
        id="username"
        type="text"
        onChange={handleChange}
        value={formState.username}
      />
      <label htmlFor="password">Password:</label>
      <input
        id="password"
        type="password"
        onChange={handleChange}
        value={formState.password}
      />
      <button type="submit">Login</button>
    </form>
  );
}
export default LoginForm;

We call these form elements "controlled" because we're allowing React to control the value of them. Let's breakdown the pattern:

Step 1. Start with an Object in State

When working with forms, it's helpful to have all of the values in a single object. Most often, this is how our APIs will want us to send the data to them. We'll learn more about sending data to APIs in the next unit, but using this pattern will make it easy for us to work with them in the future. An object that contains a property for each input inside the form will work well for 90% of our use cases. Assume we have a wireframe for a form like this:

Form wireframe

We could have an object that represents it like this:

const initialState = {
  issueType: '',
  subject: '',
  message: '',
};
const [formState, setFormState] = useState(initialState);

Step 2. Build the Basic Form

Following best practices for form accessibility, build a JSX form that renders the corresponding HTML:

//...
return (
  <form>
    <label htmlFor="issueType">Type of Issue:</label>
    <select id="issueType">
      <option value="outage">Service Outage</option>
      <option value="billing">Billing</option>
      <option value="cancel">Cancel Service</option>
    </select>
    <label htmlFor="subject">Subject:</label>
    <input type="text" id="subject" />
    <label htmlFor="message">Message</label>
    <textarea id="message" cols="30" rows="10"></textarea>
    <button type="submit">Send</button>
  </form>
);
//...

Remember that JSX is JavaScript, so we can't use a reserved word like for as an attribute in our label elements. Also, note that we have a button with a type of submit. All buttons that do not have a type attribute act as a submit for forms by default in HTML, but it's good practice to be specific.

Step 3. Add the Form Submit Handler

By convention, we'll give our form submit handler the name handleSubmit. We'll then use the event that the browser passes to it, to prevent the page from being refreshed. When we're done doing what we need to with the data, we can clear the form by resetting it to it's initialState.

// Event Handler: a callback function to
// be run when the event is observed
const handleSubmit = (event) => {
  // we always need to stop the browser
  // from submitting the form or the page
  // will be refreshed.
  event.preventDefault();
  // do something with the data in the component state
  console.log(formState);
  // clear the form
  setFormState(initialState);
};

// Event Listener: tells the browser
// which event to listen for on which
// element and what to do when the event
// happens
<form onSubmit={handleSubmit}>

Step 4. Connect the Form Fields to State

Here's where the real magic happens! This is where our form's fields become controlled and automatically update our state.

We'll start with another event handler. This is the handler that will run every time there is a change to one of our form fields. All HTML form elements have a change event. We listen for this event to make sure that we have a generic handler. Every form element also has a value property that remembers the value the user entered in it or chose. Again, by convention only, we'll name this handler handleChange.

const handleChange = (event) => {
  setFormState({ ...formState, [event.target.id]: event.target.value });
};

Hmmm... This looks weird. What are the three dots there? That's called the spread syntax and it's awesome!

Now, that we have our handleChange event handler, we need to connect all of the form elements to it.

Add an onChange attribute to each element and reference the handleChange function as it's value.

Lastly, we just have to connect each element's value attribute to it's corresponding property in the formState.

<form onSubmit={handleSubmit}>
  <label htmlFor="issueType">Type of Issue:</label>
  <select id="issueType" onChange={handleChange} value={formState.issueType}>
    <option value="outage">Service Outage</option>
    <option value="billing">Billing</option>
    <option value="cancel">Cancel Service</option>
  </select>
  <label htmlFor="subject">Subject:</label>
  <input
    type="text"
    id="subject"
    onChange={handleChange}
    value={formState.subject}
  />
  <label htmlFor="message">Message</label>
  <textarea
    id="message"
    cols="30"
    rows="10"
    onChange={handleChange}
    value={formState.message}
  ></textarea>
  <button type="submit">Send</button>
</form>

Done! A totally generic and reusable way to handle forms in React.

Additional Resources

All content is licensed under a CC­BY­NC­SA 4.0 license.

All software code is licensed under GNU GPLv3. For commercial use or alternative licensing, please contact legal@ga.co.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published