Categories
JavaScript React

How to Handle Forms With React

Spread the love

In this article, we’ll look at how to handle forms with React.


Form Handling

The standard way to handle form input value changes is to handle them with React. This is a technique called controlled components.

We can create controlled components with input, textarea, and select elements. They maintain their own state, and updates are based on user input.

Like with anything else, the component state is updated with setState(). This means that we have to call it with the value of the input elements to update the state with the inputted values.

To update the state with the inputted value, we can write the following:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: "" };
  }
  handleChange(event) {
    this.setState({ name: event.target.value });
  }
  handleSubmit(event) {
    alert(`Name submiited: ${this.state.name}`);
    event.preventDefault();
  }
  render() {
    return (
      <div className="App">
        <form onSubmit={this.handleSubmit.bind(this)}>
          <label>
            Name:
            <input
              type="text"
              value={this.state.name}
              onChange={this.handleChange.bind(this)}
            />
          </label>
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }

In the code above, we have the input element that has an onChange handler which is set to this.handleChange. The handleChange method has the code to update this.state.name with the latest inputted value. event.target.value has the latest value.

Then, we attached an onSubmit handler to the form, which is set to this.handleSubmit.

We call event.preventDefault to prevent the default submit action, so we can run JavaScript code in the handler to display the alert box with the latest inputted value.

The handler methods make it easy to handle input validation. We can also manipulate it there. For example, we can change our input value before updating the state as follows:

handleChange(event) {  
  this.setState({name: event.target.value.toLowerCase()});  
}

We don’t have to create an extra function to change our input to lowercase before setting it to this.state.name.

We have the value prop to set the value to the latest state so that we can see our inputted value.


The textarea Tag

Like with handling input elements, we can handle value changes with textarea elements the same way.

We can write the following to set the state to the latest inputted value:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { essay: "" };
  }
  handleChange(event) {
    this.setState({ essay: event.target.value });
  }
  handleSubmit(event) {
    alert(`Essay submiited: ${this.state.essay}`);
    event.preventDefault();
  }
  render() {
    return (
      <div className="App">
        <form onSubmit={this.handleSubmit.bind(this)}>
          <label>Essay:</label>
          <br />
          <textarea
            type="text"
            value={this.state.essay}
            onChange={this.handleChange.bind(this)}
          />
          <br />
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

It’s pretty much the same as the code for handling inputted values from the input element, but we have a textarea element instead.


The select Tag

The select element creates a drop-down where we can select more values.

We can write the following code to get the selection from the drop-down and set it to the state:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { fruit: "apple" };
  }
  handleChange(event) {
    this.setState({ fruit: event.target.value });
  }
  handleSubmit(event) {
    alert(`Favorite fruit: ${this.state.fruit}`);
    event.preventDefault();
  }
  render() {
    return (
      <div className="App">
        <form onSubmit={this.handleSubmit.bind(this)}>
          <label>Favorite Fruit:</label>
          <br />
          <select
            onChange={this.handleChange.bind(this)}
            value={this.state.fruit}
          >
            <option value="apple">Apple</option>
            <option value="orange">Orange</option>
            <option value="mango">Mango</option>
          </select>
          <br />
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

As we can see, it’s almost the same as the other examples, except that we have a select element with option elements inside instead.

select elements also work for getting multiple selections. We can update the state with all the selections by getting the options available, getting the ones that are selected, and putting them in an array as follows:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { fruits: [] };
  }
  handleChange(event) {
    const options = event.target.options;
    const fruits = [];
    for (const option of options) {
      if (option.selected) {
        fruits.push(option.value);
      }
    }
    this.setState({ fruits });
  }
  handleSubmit(event) {
    alert(`Favorite fruit: ${this.state.fruits.join(",")}`);
    event.preventDefault();
  }
  render() {
    return (
      <div className="App">
        <form onSubmit={this.handleSubmit.bind(this)}>
          <label>Favorite Fruit:</label>
          <br />
          <select
            multiple
            onChange={this.handleChange.bind(this)}
            value={this.state.fruits}
          >
            <option value="apple">Apple</option>
            <option value="orange">Orange</option>
            <option value="mango">Mango</option>
          </select>
          <br />
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

In the code, we have:

handleChange(event) {
  const options = event.target.options;
  const fruits = [];
  for (const option of options) {
    if (option.selected) {
      fruits.push(option.value);
    }
  }
  this.setState({ fruits });
}

In the first line of the function, we have:

const options = event.target.options;

Which has all the options from the select element.

Then, we can loop through the options and check the selected property of each and then push them to the array if selected is true. We then call setState with fruits to update the state with the latest selected values.

In handleSubmit, we can this.state.fruits and call join on it with a comma to convert it to a comma-separated string.

Also, the value prop of the select element takes an array instead of a string. React is smart enough to parse the array and render the selected values.


Handling Multiple Inputs

When we need to handle multiple inputs, we don’t want to make a new onChange handler function for each input. Therefore, we want to make a function that can set all values.

We can do that as follows:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { firstName: "", lastName: "" };
  }
  handleChange(event) {
    const target = event.target;
    const value = target.value;
    const name = target.name;
    this.setState({
      [name]: value
    });
  }
  handleSubmit(event) {
    alert(`Name ${this.state.firstName} ${this.state.lastName}`);
    event.preventDefault();
  }
  render() {
    return (
      <div className="App">
        <form onSubmit={this.handleSubmit.bind(this)}>
          <label>First Name:</label>
          <br />
          <input
            name="firstName"
            onChange={this.handleChange.bind(this)}
            value={this.state.firstName}
          />
          <br />
          <label>Last Name:</label>
          <br />
          <input
            name="lastName"
            onChange={this.handleChange.bind(this)}
            value={this.state.lastName}
          />
          <br />
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

In the code above, we have the following handleChange method:

handleChange(event) {
  const target = event.target;
  const value = target.value;
  const name = target.name;
  this.setState({
    [name]: value
  });
}

We get the event.target object and set it to target. The target has the name and value properties that have the input’s name and value attribute values respectively.

Therefore, we can take advantage of ES6’s dynamic object property feature and call setState with the name as the property name and value as the value to update the state.


Conclusion

We should handle input changes by writing controlled components. To do this, we attach an event handler function to the onChange event.

To handle form submit, we attach an onSubmit event handler to the form, and then get the event object from the parameter and call event.preventDefault inside so we can run JavaScript code in the handler.

To handle multiple input changes with one onChange handler, we get the name and value properties from event.target from the handler’s parameter and update it with the dynamic property name feature available since ES6.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *