controlled forms in react
Tags: javascript, react, programming, webdev
Published: 2021-10-25 17:58:15

**A *controlled form* is** used to submit data to be persisted to a database that derives its input value from `state`. The alternative to a *controlled form* is an *uncontrolled form*, in which the data is handled not by `state` but, instead, by the DOM. Simply put, in a controlled form, `state` is aware of the characters being typed into any given form field at any given time. If a *controlled form* had a parenting style, it would be a helicopter parent, where an *uncontrolled form* would be a mega-chill and sort of 'hands off' parent, not totally paying attention but still kinda' there. 

One good way to tell the difference between a *controlled form* or *uncontrolled form*, is to check for `value` or for `defaultValue`. If the component has a `value` `prop`, it is a *controlled component*. If it does not have a `value` `prop`, it is an *uncontrolled component*. An *uncontrolled component* can optionally have a `defaultValue` `prop` set to its initial value -- but -- if the component has a `value` `prop`, it is a *controlled component*. 

**How does it work, you ask?** Let's walk through. I arrive at a browser window which is rendering a *controlled form*. It wants my first name. 

The current `state` looks like this 
```
   state = {
       name: '',
   }
```
I start to type my name, I hit the letter 'M' on my keyboard. Now, `state` looks like this 
```
   state = {
       name: 'M',
   }
```
I continue typing my name, but then I accidentally hit the wrong key. `state` looks like this now 
```
   state = {
       name: 'Mau',
   }
```
I realize my error. `state` looks like this,
```
   state = {
       name: 'Ma',
   }
```
and I correct my mistake. `state` looks like this.
```
   state = {
       name: 'May',
   }
```
Before I even press the 'submit' button on the form, `state` already knows my name. That's accomplished through the following event handler 
```
handleChange = e => {
       const { name, value } = e.target
       this.setState({
           [name]: value
       })
}
```
Which is invoked inside of the *controlled form* by the event listener on line five 
```
    <form onSubmit={this.handleSubmit}>
      <label>your name:</label>
      <input type="text">
       value={this.state.name}
       onChange={this.handleChange}
       name="name"/>
      <br/>
      <input type="submit" value="submit"/>
    </form>
```
These guys work together and say *"as soon as there is a change in the form field, we're going to handle that change by passing and destructuring the data provided in the form field and setting it equal to the current* `state`". 

Pretty cool. 

Now that I've entered my name, I'm ready to hit the 'submit' button. Here we have another event listener & handler ready to send the data from the form field to the database and reset state 
```
handleSubmit = e => {
    e.preventDefault();
    this.props.addPerson(this.state)
 
    this.setState({
        name: ''
    })
}
```
This event handler is invoked inside of the *controlled form* when I press the 'submit' button. My name is then couriered to the database, and `state` looks like this again now, just like it did at the beginning 
```
   state = {
       name: '',
   }
```
**Why do we do it this way?** *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`. Another reason *controlled forms* are preferred is that *uncontrolled forms* typically yield code that is not DRY. In an *uncontrolled form*, one may access the form data within the event -- that is to say, the data is available 
```
handleSubmit = e => {
 e.preventDefault()
 const carMake = e.target.children[0].value
 const carModel = e.target.children[1].value
 this.persistDataToDatabase({ carMake, carModel 
 })
}
```
*but*, it is just not quite as efficient, or elegant as the alternative, a *controlled component*. 
```
handleSubmit = e => {
 e.preventDefault()
 this.persistDataToDatabase(this.state)
}
```
Thanks for reading!