~/Home ~/Notes ~/Categories

React Forms

30 August, 2020  ·   React
  https://www.udemy.com/course/modern-react-bootcamp/

Note: These notes are taken from Colt steele’s Modern React Bootcamp course

Forms

1<form>
2  <label for="fullname">Full Name:</label>
3  <input name="fullname" />
4  <button>Add!</button>
5</form>

Thinking About State

1<form>
2  <label for="fullname">Full Name:</label>
3  <input name="fullname" />
4  <button>Add!</button>
5</form>

It’s convenient to have a JS function that handles the submission of the form and has access to the data the user entered.

The technique to get this is controlled components.

Controlled Components

How do we use React to control form input state?

One Source of Truth

Input elements controlled in this way are called “controlled components”.

Example Form Component

 1class NameForm extends Component {
 2  constructor(props) {
 3    super(props);
 4    // default fullName is an empty string
 5    this.state = { fullName: "" };
 6    this.handleChange = this.handleChange.bind(this);
 7    this.handleSubmit = this.handleSubmit.bind(this);
 8  }
 9
10  handleSubmit(evt) {
11    // do something with form data
12  }
13  handleChange(evt) {
14    // runs on every keystroke event
15  }
16
17  render() {
18    return (
19      <form onSubmit={this.handleSubmit}>
20        <label htmlFor="fullname">Full Name:</label>
21        <input
22          name="fullname"
23          value={this.state.fullName}
24          onChange={this.handleChange}
25        />
26        <button>Add!</button>
27      </form>
28    );
29  }
30}

How the Controlled Form Works

handleChange Method

Here is the method that updates state based on input.

 1class NameForm extends Component {
 2  // ...
 3
 4  handleChange(evt) {
 5    // runs on every keystroke
 6    this.setState({
 7      fullName: evt.target.value,
 8    });
 9  }
10
11  // ...
12}

Handling Multiple Inputs

Computed Property Names

ES5

1var catData = {};
2var microchip = 1432345421;
3catData[microchip] = "Blue Steele";

ES2015

1let microchip = 1432345421;
2let catData = {
3  // propery computed inside the object literal
4  [microchip]: "Blue Steele",
5};

Application To React Form Components

Instead of making a separate onChange handler for every single input, we can make one generic function for multiple inputs!

Handling Multiple Inputs

To handle multiple controlled inputs, add the HTML name attribute to each JSX input element and let handler function decide the appropriate key in state to update based on event.target.name.

 1class YourComponent extends Component {
 2  // ...
 3
 4  handleChange(evt) {
 5    this.setState({
 6      [evt.target.name]: evt.target.value,
 7    });
 8  }
 9
10  // ...
11}

Using this method, the keys in state have to match the input name attributes exactly.

The state:

1this.state = { firstName: "", lastName: "" };

NameForm.js;

 1class NameForm extends Component {
 2  handleChange(evt) {
 3    this.setState({ [evt.target.name]: evt.target.value });
 4  }
 5
 6  render() {
 7    return (
 8      <form onSubmit={this.handleSubmit}>
 9        <label htmlFor="firstName">First:</label>
10        <input
11          id="firstName"
12          name="firstName"
13          value={this.state.firstName}
14          onChange={this.handleChange}
15        />
16
17        <label htmlFor="lastName">Last:</label>
18        <input
19          id="lastName"
20          name="lastName"
21          value={this.state.lastName}
22          onChange={this.handleChange}
23        />
24        <button>Add a new person!</button>
25      </form>
26    );
27  }
28} // end

Design pattern: Passing Data Up to a Parent Component

In React we generally have downward data flow. “Smart” parent components with simpler child components.

Shopping List Example

ShoppingList.js

 1class ShoppingList extends Component {
 2  /* Add new item object to cart. */
 3  addItem(item) {
 4    let newItem = { ...item, id: uuid() };
 5    this.setState((state) => ({
 6      items: [...state.items, newItem],
 7    }));
 8  }
 9
10  render() {
11    return (
12      <div className="ShoppingList">
13        <NewListItemForm addItem={this.addItem} />
14        {this.renderItems()}
15      </div>
16    );
17  }
18}

NewListItemForm.js

1class NewListItemForm extends Component {
2  // Send {name, quantity} to parent - & clear form.
3
4  handleSubmit(evt) {
5    evt.preventDefault();
6    this.props.addItem(this.state);
7    this.setState({ name: "", qty: 0 });
8  }
9}

Keys and UUIDs

Using UUID for Unique Keys

Using the UUID Module

ShoppingList.js

1import uuid from "uuid/v4";

ShoppingList.js

 1class ShoppingList extends Component {
 2  constructor(props) {
 3    super(props);
 4    this.state = {
 5      items: [
 6        { name: "Milk", qty: "2 gallons", id: uuid() },
 7        { name: "Bread", qty: "2 loaves", id: uuid() },
 8      ],
 9    };
10    this.addItem = this.addItem.bind(this);
11  }
12  addItem(item) {
13    let newItem = { ...item, id: uuid() };
14    this.setState((st) => ({
15      items: [...st.items, newItem],
16    }));
17  }
18  renderItems() {
19    return (
20      <ul>
21        {this.state.items.map((item) => (
22          <li key={item.id}>
23            {item.name}:{item.qty}
24          </li>
25        ))}
26      </ul>
27    );
28  }
29}

Validation

 react  javascript  es6
React Events↠ ↞React Lifecycle Methods