Skip to content

React Forms

sergio edited this page Jan 23, 2021 · 4 revisions
index

Controlled Form

A controlled form is a form that derives its input values from state.

import React from 'react';

class Form extends React.Component {
  state = {
    firstName: "John",
    lastName: "Henry"
  }

  render() {
    return (
      <form>
        <input type="text" name="firstName" value={this.state.firstName} />
        <input type="text" name="lastName" value={this.state.lastName} />
      </form>
    )
  }
}

export default Form;

To completely control a form, we also need our form to update state every time the form changes. Forms should display whatever changes a user makes. For this, we use an event listener onChange that React has set up for us:

<input type="text" onChange={event => this.handleFirstNameChange(event)} value={this.state.firstName} />
<input type="text" onChange={event => this.handleLastNameChange(event)} value={this.state.lastName} />
handleFirstNameChange = event => {
  this.setState({
    firstName: event.target.value
  })
}

handleLastNameChange = event => {
  this.setState({
    lastName: event.target.value
  })
}

In the handleFirstNameChange() and handleLastNameChange() methods, we're updating state based on event.target.value. This, in turn, causes a re-render... and the cycle completes. The new state values we just set are used to set the value attributes of our two inputs. From a user's perspective, the form behaves exactly how we'd expect, displaying the text that is typed. From React's perspective, we gain control over form values, giving us the ability to more easily manipulate (or restrict) what our inputss display.

Controlling forms makes it more convenient to share form values between components. Since the form values are stored in state, they are easily passed down as props or sent upward via a function supplied in props.

To submit our form we use a second event onSubmit added to the form in JSX. here is a complete Form Component where though we don't have a server to send our data to, but we modify our Form component to list out submissions, storing them in state:

import React from 'react';

class Form extends React.Component {
  state = {
    firstName: "John",
    lastName: "Henry",
    submittedData: []
  }

  handleFirstNameChange = event => {
    this.setState({
      firstName: event.target.value
    })
  }

  handleLastNameChange = event => {
    this.setState({
      lastName: event.target.value
    })
  }

  handleSubmit = event => {
    event.preventDefault()
    let formData = { firstName: this.state.firstName, lastName: this.state.lastName }
    let dataArray = this.state.submittedData.concat(formData)
    this.setState({submittedData: dataArray})
  }

  listOfSubmissions = () => {
    return this.state.submittedData.map(data => {
      return <div><span>{data.firstName}</span> <span>{data.lastName}</span></div>
    })
  }

  render() {
    return (
      <div>
        <form onSubmit={event => this.handleSubmit(event)}>
          <input
            type="text"
            onChange={event => this.handleFirstNameChange(event)}
            value={this.state.firstName}
          />
          <input
            type="text"
            onChange={event => this.handleLastNameChange(event)}
            value={this.state.lastName}
          />
          <input type="submit"/>
        </form>
        {this.listOfSubmissions()}
      </div>
    )
  }
}

export default Form;

A form, when submitted should send the form data somewhere. As mentioned a moment ago, the traditional HTML way was to send data to a server or another page using the action attribute. In React, we handle requests with asynchronous JavaScript. We won't go into the details of how this works just yet, but we can think of sendFormDataSomewhere() as the code that handles sending our data off.

Controlled Vs Uncontrolled Components

React provides us with two ways of setting and getting values in form elements. These two methods are called uncontrolled and controlled components. The differences are subtle, but it's important to recognize them — and use them accordingly (spoiler: most of the time, we'll use controlled components).

The quickest way to check if a component is controlled or uncontrolled is to check for value or defaultValue. If the component has a value prop, it is controlled (the state of the component is being controlled by React). If it doesn't have a value prop, it's an uncontrolled component. Uncontrolled components can optionally have a defaultValue prop to set its initial value. These two props (value and defaultValue) are mutually exclusive: a component is either controlled or uncontrolled, but it cannot be both.

The main difference is that in uncontrolled forms the state (the values of 'value=') is internal to the HTML form itself.

Uncontrolled Componenet

All the form data in an uncontrolled form is accessible within the event, but accessing can sometimes be a pain, as you end up writing things like event.target.children[0].value to get the value of our first input.

handleSubmit = event => {
  event.preventDefault()
  const firstName = event.target.children[0].value
  const lastName = event.target.children[1].value
  this.sendFormDataSomewhere({ firstName, lastName })
}

On a larger form this can turn into some dense code.

Controlled Component

In controlled components, we explicitly set the value of a component using state, and update that value in response to any changes the user makes. While it takes a little bit of set up to implement, it makes some other parts of our code easier. For instance, in a basic controlled form, our handleSubmit() function can be relatively simple:

handleSubmit = event => {
  event.preventDefault()
  this.sendFormDataSomewhere(this.state)
}

If our entire state object is just the controlled form data, we can send the entire object around wherever it needs to go. Not only that, if we expanded our form to have 20 controlled inputs, this handleSubmit doesn't change. It just sends all 20 state values wherever we need them to go upon submission.

Clone this wiki locally