You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
270 lines
8.8 KiB
270 lines
8.8 KiB
8 years ago
|
---
|
||
|
id: forms
|
||
|
title: Forms
|
||
|
permalink: docs/forms.html
|
||
8 years ago
|
prev: lists-and-keys.html
|
||
8 years ago
|
next: lifting-state-up.html
|
||
8 years ago
|
redirect_from:
|
||
|
- "tips/controlled-input-null-value.html"
|
||
|
- "docs/forms-zh-CN.html"
|
||
8 years ago
|
---
|
||
|
|
||
8 years ago
|
HTML form elements work a little bit differently from other DOM elements in React, because form elements naturally keep some internal state. For example, this form in plain HTML accepts a single name:
|
||
8 years ago
|
|
||
8 years ago
|
```html
|
||
|
<form>
|
||
8 years ago
|
<label>
|
||
|
Name:
|
||
|
<input type="text" name="name" />
|
||
|
</label>
|
||
8 years ago
|
<input type="submit" value="Submit" />
|
||
|
</form>
|
||
|
```
|
||
8 years ago
|
|
||
8 years ago
|
This form has the default HTML form behavior of browsing to a new page when the user submits the form. If you want this behavior in React, it just works. But in most cases, it's convenient to have a JavaScript function that handles the submission of the form and has access to the data that the user entered into the form. The standard way to achieve this is with a technique called "controlled components".
|
||
8 years ago
|
|
||
|
## Controlled Components
|
||
|
|
||
7 years ago
|
In HTML, form elements such as `<input>`, `<textarea>`, and `<select>` typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the state property of components, and only updated with [`setState()`](/docs/react-component.html#setstate).
|
||
8 years ago
|
|
||
8 years ago
|
We can combine the two by making the React state be the "single source of truth". Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a "controlled component".
|
||
8 years ago
|
|
||
8 years ago
|
For example, if we want to make the previous example log the name when it is submitted, we can write the form as a controlled component:
|
||
8 years ago
|
|
||
8 years ago
|
```javascript{4,10-12,24}
|
||
8 years ago
|
class NameForm extends React.Component {
|
||
8 years ago
|
constructor(props) {
|
||
|
super(props);
|
||
8 years ago
|
this.state = {value: ''};
|
||
8 years ago
|
|
||
|
this.handleChange = this.handleChange.bind(this);
|
||
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||
|
}
|
||
|
|
||
|
handleChange(event) {
|
||
|
this.setState({value: event.target.value});
|
||
|
}
|
||
|
|
||
|
handleSubmit(event) {
|
||
8 years ago
|
alert('A name was submitted: ' + this.state.value);
|
||
|
event.preventDefault();
|
||
8 years ago
|
}
|
||
|
|
||
|
render() {
|
||
|
return (
|
||
8 years ago
|
<form onSubmit={this.handleSubmit}>
|
||
8 years ago
|
<label>
|
||
|
Name:
|
||
|
<input type="text" value={this.state.value} onChange={this.handleChange} />
|
||
|
</label>
|
||
8 years ago
|
<input type="submit" value="Submit" />
|
||
|
</form>
|
||
8 years ago
|
);
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
8 years ago
|
[Try it on CodePen.](https://codepen.io/gaearon/pen/VmmPgp?editors=0010)
|
||
8 years ago
|
|
||
8 years ago
|
Since the `value` attribute is set on our form element, the displayed value will always be `this.state.value`, making the React state the source of truth. Since `handleChange` runs on every keystroke to update the React state, the displayed value will update as the user types.
|
||
8 years ago
|
|
||
8 years ago
|
With a controlled component, every state mutation will have an associated handler function. This makes it straightforward to modify or validate user input. For example, if we wanted to enforce that names are written with all uppercase letters, we could write `handleChange` as:
|
||
8 years ago
|
|
||
8 years ago
|
```javascript{2}
|
||
|
handleChange(event) {
|
||
|
this.setState({value: event.target.value.toUpperCase()});
|
||
|
}
|
||
8 years ago
|
```
|
||
|
|
||
8 years ago
|
## The textarea Tag
|
||
8 years ago
|
|
||
8 years ago
|
In HTML, a `<textarea>` element defines its text by its children:
|
||
8 years ago
|
|
||
|
```html
|
||
8 years ago
|
<textarea>
|
||
|
Hello there, this is some text in a text area
|
||
|
</textarea>
|
||
8 years ago
|
```
|
||
|
|
||
8 years ago
|
In React, a `<textarea>` uses a `value` attribute instead. This way, a form using a `<textarea>` can be written very similarly to a form that uses a single-line input:
|
||
8 years ago
|
|
||
8 years ago
|
```javascript{4-6,12-14,26}
|
||
8 years ago
|
class EssayForm extends React.Component {
|
||
8 years ago
|
constructor(props) {
|
||
|
super(props);
|
||
8 years ago
|
this.state = {
|
||
|
value: 'Please write an essay about your favorite DOM element.'
|
||
|
};
|
||
|
|
||
8 years ago
|
this.handleChange = this.handleChange.bind(this);
|
||
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||
|
}
|
||
8 years ago
|
|
||
8 years ago
|
handleChange(event) {
|
||
|
this.setState({value: event.target.value});
|
||
|
}
|
||
|
|
||
|
handleSubmit(event) {
|
||
8 years ago
|
alert('An essay was submitted: ' + this.state.value);
|
||
|
event.preventDefault();
|
||
8 years ago
|
}
|
||
|
|
||
|
render() {
|
||
|
return (
|
||
8 years ago
|
<form onSubmit={this.handleSubmit}>
|
||
8 years ago
|
<label>
|
||
|
Name:
|
||
|
<textarea value={this.state.value} onChange={this.handleChange} />
|
||
|
</label>
|
||
8 years ago
|
<input type="submit" value="Submit" />
|
||
|
</form>
|
||
8 years ago
|
);
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
8 years ago
|
Notice that `this.state.value` is initialized in the constructor, so that the text area starts off with some text in it.
|
||
8 years ago
|
|
||
8 years ago
|
## The select Tag
|
||
8 years ago
|
|
||
8 years ago
|
In HTML, `<select>` creates a drop-down list. For example, this HTML creates a drop-down list of flavors:
|
||
8 years ago
|
|
||
8 years ago
|
```html
|
||
|
<select>
|
||
|
<option value="grapefruit">Grapefruit</option>
|
||
|
<option value="lime">Lime</option>
|
||
|
<option selected value="coconut">Coconut</option>
|
||
|
<option value="mango">Mango</option>
|
||
|
</select>
|
||
8 years ago
|
```
|
||
|
|
||
8 years ago
|
Note that the Coconut option is initially selected, because of the `selected` attribute. React, instead of using this `selected` attribute, uses a `value` attribute on the root `select` tag. This is more convenient in a controlled component because you only need to update it in one place. For example:
|
||
8 years ago
|
|
||
8 years ago
|
```javascript{4,10-12,24}
|
||
8 years ago
|
class FlavorForm extends React.Component {
|
||
8 years ago
|
constructor(props) {
|
||
|
super(props);
|
||
8 years ago
|
this.state = {value: 'coconut'};
|
||
|
|
||
8 years ago
|
this.handleChange = this.handleChange.bind(this);
|
||
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||
|
}
|
||
|
|
||
|
handleChange(event) {
|
||
|
this.setState({value: event.target.value});
|
||
|
}
|
||
|
|
||
|
handleSubmit(event) {
|
||
8 years ago
|
alert('Your favorite flavor is: ' + this.state.value);
|
||
|
event.preventDefault();
|
||
8 years ago
|
}
|
||
|
|
||
|
render() {
|
||
|
return (
|
||
8 years ago
|
<form onSubmit={this.handleSubmit}>
|
||
8 years ago
|
<label>
|
||
|
Pick your favorite La Croix flavor:
|
||
|
<select value={this.state.value} onChange={this.handleChange}>
|
||
|
<option value="grapefruit">Grapefruit</option>
|
||
|
<option value="lime">Lime</option>
|
||
|
<option value="coconut">Coconut</option>
|
||
|
<option value="mango">Mango</option>
|
||
|
</select>
|
||
|
</label>
|
||
8 years ago
|
<input type="submit" value="Submit" />
|
||
|
</form>
|
||
8 years ago
|
);
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
8 years ago
|
[Try it on CodePen.](https://codepen.io/gaearon/pen/JbbEzX?editors=0010)
|
||
8 years ago
|
|
||
8 years ago
|
Overall, this makes it so that `<input type="text">`, `<textarea>`, and `<select>` all work very similarly - they all accept a `value` attribute that you can use to implement a controlled component.
|
||
8 years ago
|
|
||
7 years ago
|
> Note
|
||
|
>
|
||
|
> You can pass an array into the `value` attribute, allowing you to select multiple options in a `select` tag:
|
||
|
>
|
||
|
>```js
|
||
|
><select multiple={true} value={['B', 'C']}>
|
||
|
>```
|
||
|
|
||
8 years ago
|
## Handling Multiple Inputs
|
||
|
|
||
8 years ago
|
When you need to handle multiple controlled `input` elements, you can add a `name` attribute to each element and let the handler function choose what to do based on the value of `event.target.name`.
|
||
8 years ago
|
|
||
8 years ago
|
For example:
|
||
|
|
||
|
```javascript{15,18,28,37}
|
||
8 years ago
|
class Reservation extends React.Component {
|
||
|
constructor(props) {
|
||
|
super(props);
|
||
|
this.state = {
|
||
8 years ago
|
isGoing: true,
|
||
|
numberOfGuests: 2
|
||
8 years ago
|
};
|
||
|
|
||
|
this.handleInputChange = this.handleInputChange.bind(this);
|
||
|
}
|
||
|
|
||
|
handleInputChange(event) {
|
||
|
const target = event.target;
|
||
|
const value = target.type === 'checkbox' ? target.checked : target.value;
|
||
|
const name = target.name;
|
||
|
|
||
|
this.setState({
|
||
|
[name]: value
|
||
|
});
|
||
|
}
|
||
|
|
||
|
render() {
|
||
|
return (
|
||
8 years ago
|
<form>
|
||
|
<label>
|
||
|
Is going:
|
||
|
<input
|
||
|
name="isGoing"
|
||
|
type="checkbox"
|
||
|
checked={this.state.isGoing}
|
||
|
onChange={this.handleInputChange} />
|
||
|
</label>
|
||
|
<br />
|
||
|
<label>
|
||
|
Number of guests:
|
||
|
<input
|
||
|
name="numberOfGuests"
|
||
|
type="number"
|
||
|
value={this.state.numberOfGuests}
|
||
|
onChange={this.handleInputChange} />
|
||
|
</label>
|
||
|
</form>
|
||
8 years ago
|
);
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
8 years ago
|
[Try it on CodePen.](https://codepen.io/gaearon/pen/wgedvV?editors=0010)
|
||
8 years ago
|
|
||
8 years ago
|
Note how we used the ES6 [computed property name](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names) syntax to update the state key corresponding to the given input name:
|
||
|
|
||
|
```js{2}
|
||
|
this.setState({
|
||
|
[name]: value
|
||
|
});
|
||
|
```
|
||
|
|
||
|
It is equivalent to this ES5 code:
|
||
|
|
||
|
```js{2}
|
||
8 years ago
|
var partialState = {};
|
||
|
partialState[name] = value;
|
||
|
this.setState(partialState);
|
||
8 years ago
|
```
|
||
|
|
||
7 years ago
|
Also, since `setState()` automatically [merges a partial state into the current state](/docs/state-and-lifecycle.html#state-updates-are-merged), we only needed to call it with the changed parts.
|
||
8 years ago
|
|
||
8 years ago
|
## Alternatives to Controlled Components
|
||
8 years ago
|
|
||
7 years ago
|
It can sometimes be tedious to use controlled components, because you need to write an event handler for every way your data can change and pipe all of the input state through a React component. This can become particularly annoying when you are converting a preexisting codebase to React, or integrating a React application with a non-React library. In these situations, you might want to check out [uncontrolled components](/docs/uncontrolled-components.html), an alternative technique for implementing input forms.
|