Forms

Forms are different from other HTML elements. They keep track of their state through properties such as value, checked, etc.

As an example, let's use the following form. We're going to want to keep track of the value of the input when the user types:

<form>
  <label>
    Name:<input type="text">
  </label>
  <input type="submit" value="Submit">
</form>

We will need to create the form with the render function of a class component. We'll track the input changes with an inline event for now. We'll give the form element a onsubmit event handler.

See the Pen Composi Tuts - Forms-1 by Robert Biggs (@rbiggs) on CodePen.

Now the state of the form is owned by the component. As the user enters data in the input, it value is being set on the component's state. This keeps the component state insynch with the form at all times.

You can use this same technique on textareas, checkboxes, radio buttons, etc. to keep track of their state in a component.

The Select Tag

This one is a bit tricky. That's because its selection is determined by the value of its selectedIndex property. Let's look at the follow example where are form has a select tag. We want to render it with a default value other than the first options. We want it to render showing Coconut" as the selection:

See the Pen Composi Tuts - Forms-2 by Robert Biggs (@rbiggs) on CodePen.

We've set the default value as "coconut" in the state assignment in the class constructor. With this you would expect to see that as the choice when the component renders. However, that is not what happens. The select tag renders showing the first option: "Grapefuit". However, if we click on the button, it alerts "Your favorite flavor is: coconut". Just what we would expect. Why isn't the correct selection showing. That's because of the select tag's property of selectedIndex. That property determines what option is shown.

What Went Wrong

So why doesn't this work? Because of how we rendered the select tag. Rendering it with a value does not cause the selectedIndex to be set. Normally, if you set the value of a select tag, that will trigger setting the correct selectedIndex value. In this case, there was no setting of the value. We rendered the select tag to the DOM with the value. That's why we can alert the value.

Call in the LifeCycle Hook!

If you want to show a selection other than the default first option, you will need to do so right after the component is create. For this you can take advantage of the component's lifecylcy hook: componentWasCreate. You can use that to set the value of the select:

componentDidMount() {
  // Set the value of the component's select tag, 
  // after the component was created:
  this.element.querySelector('select').value = this.state.value
}

When we add the above method to the component, the select tag renders showing the default value of "Coconut". Setting the select tag's state in the componentDidMount hook causes the selectedIndex value to also be set. Problem solved:

See the Pen Composi Tuts - Forms-3 by Robert Biggs (@rbiggs) on CodePen.

Setting Default Values

You can also use the componentWasCreate lifecycle hook to set the default values on form elements. Remember, you can easily query any child elements in a component through its this.element property, just as we did above to get the select tag.

Handling a Form with Many Inputs

If a form has a lot of inputs, trying to keep tract of all of them in your component's state can be difficult. In such a case you want to take another route. Don't bother trying to control the form state with the component state. Let the form be. Instead, at submit time, gather up all the form inputs and then set them to the form's state.

Let's take our previous example of NameForm and make it work without tracking the input value. Instead we'll just get the value of the input and use that. We can get the input through the component's element property. In the following form we are going to track the value of a checkbox and input. When their state changes, we will output the changes below:

See the Pen Composi Tuts - Forms-4 by Robert Biggs (@rbiggs) on CodePen.