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.

295 lines
9.9 KiB

---
id: forms
title: Forms
permalink: docs/forms.html
prev: lists-and-keys.html
next: lifting-state-up.html
redirect_from:
- "tips/controlled-input-null-value.html"
- "docs/forms-zh-CN.html"
---
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
```html
<form>
<label>
Name:
<input type="text" name="name" />
</label>
8 years ago
<input type="submit" value="Submit" />
</form>
```
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".
## Controlled Components
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
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
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
```javascript{4,10-12,24}
8 years ago
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
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();
}
render() {
return (
8 years ago
<form onSubmit={this.handleSubmit}>
<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
[Try it on CodePen.](https://codepen.io/gaearon/pen/VmmPgp?editors=0010)
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
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
```javascript{2}
handleChange(event) {
this.setState({value: event.target.value.toUpperCase()});
}
```
8 years ago
## The textarea Tag
8 years ago
In HTML, a `<textarea>` element defines its text by its children:
```html
8 years ago
<textarea>
Hello there, this is some text in a text area
</textarea>
```
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
```javascript{4-6,12-14,26}
8 years ago
class EssayForm extends React.Component {
constructor(props) {
super(props);
8 years ago
this.state = {
value: 'Please write an essay about your favorite DOM element.'
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
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();
}
render() {
return (
8 years ago
<form onSubmit={this.handleSubmit}>
<label>
Essay:
<textarea value={this.state.value} onChange={this.handleChange} />
</label>
8 years ago
<input type="submit" value="Submit" />
</form>
);
}
}
```
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
## The select Tag
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
```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
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
```javascript{4,10-12,24}
8 years ago
class FlavorForm extends React.Component {
constructor(props) {
super(props);
8 years ago
this.state = {value: 'coconut'};
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();
}
render() {
return (
8 years ago
<form onSubmit={this.handleSubmit}>
<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
[Try it on CodePen.](https://codepen.io/gaearon/pen/JbbEzX?editors=0010)
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.
> 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']}>
>```
## The file input Tag
In HTML, an `<input type="file">` lets the user choose one or more files from their device storage to be uploaded to a server or manipulated by JavaScript via the [File API](https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications).
```html
<input type="file" />
```
Because its value is read-only, it is an **uncontrolled** component in React. It is discussed together with other uncontrolled components [later in the documentation](/docs/uncontrolled-components.html#the-file-input-tag).
## Handling Multiple Inputs
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`.
For example:
```javascript{15,18,28,37}
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
};
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 (
<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>
);
}
}
```
[Try it on CodePen.](https://codepen.io/gaearon/pen/wgedvV?editors=0010)
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}
var partialState = {};
partialState[name] = value;
this.setState(partialState);
```
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.
## Controlled Input Null Value
7 years ago
Specifying the value prop on a [controlled component](/docs/forms.html#controlled-components) prevents the user from changing the input unless you desire so. If you've specified a `value` but the input is still editable, you may have accidentally set `value` to `undefined` or `null`.
7 years ago
The following code demonstrates this. (The input is locked at first but becomes editable after a short delay.)
```javascript
ReactDOM.render(<input value="hi" />, mountNode);
setTimeout(function() {
ReactDOM.render(<input value={null} />, mountNode);
}, 1000);
```
8 years ago
## Alternatives to Controlled Components
8 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.