# 表单

* 在 React 里，HTML 表单元素的工作方式和其他的 DOM 元素有些不同，这是因为表单元素通常会保持一些内部的 state
* 表单具有默认的 HTML 表单行为，即在用户提交表单后浏览到新页面，如果你在 React 中执行相同的代码，它依然有效，

  但大多数情况下，使用 JavaScript 函数可以很方便的处理表单的提交，同时还可以访问用户填写的表单数据，实现这种效果的标准方式是 受控组件

## 受控组件

> 在 HTML 中，表单元素（如 input、textarea、select）之类的表单元素通常自己维护 state，并根据用户输入的进行更新，而在 React 中， 可变状态 mutable state 通常保存在组件的 state 属性中，并且只能通过使用 setState() 更新
>
> 我们可以把两者结合起来，使 React 的 state 成为 **唯一数据源**。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作，被 React 以这种方式控制取值的表单输入元素就叫做 受控组件

* 设置了 value 属性，显示的值始终为 this.state.value，这使得 React 的 state 成为唯一数据源
* 设置了 onChange 属性，使得每次按键时都会执行并更新 React 的 state，因此显示的值将随着用户输入而更新
* input 和 select 一致

## select

```markup
<select>
  <option value="grapefruit">葡萄柚</option>
  <option value="lime">酸橙</option>
  <option selected value="coconut">椰子</option>
  <option value="mango">芒果</option>
</select>
```

* 由于 selected 属性的缘故，椰子选项默认被选中。React 并不会使用 selected 属性，而是在根 select 标签上使用 value 属性
* 你可以将数组传递到 value 属性中，以支持在 select 标签中选择多个选项
* 总的来说，这使得 input、textarea、select之类的标签都非常相似 它们都接受一个 value 属性，你可以使用它来实现受控组件

## 文件 input

* 允许用户从存储设备中选择一个或多个文件，将其上传到服务器，或通过使用 JavaScript 的 File API 进行控制
* 因为它的 value 只读，所以它是 React 中的一个 **非受控** 组件

## 处理多个输入

* 当需要处理多个 input 元素时，我们可以给每个元素添加 name 属性，并让处理函数根据 event.target.name 的值选择要执行的操作

  \`\`\`jsx harmony

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.name === 'isGoing' ? target.checked : target.value; const name = target.name;

```
this.setState({
  [name]: value
});
```

}

render() { return (  参与: \
&#x20;来宾人数:  ); } }

````
* 这里面使用了 ES6 计算属性名称的语法更新给定输入名称对应的 state 值
```javascript

// es6
this.setState({
    [name]: value
})

// es5
var partialState = {};
partialState[name] = value;
this.setState(partialState);
````

* 由于 setState() 自动将部分 state 合并到当前 state，只需要调用它更改部分 state 即可

## 受控输入空值

* 在受控组件上指定 value 的 prop 会阻止用户更改输入，如果你指定了 value，但输入仍可编辑，则可能是你意外地将 value 设置为 undefined 或 null
* 输入最初被锁定，但在短时间延迟后变为可编辑

## 受控组件的替代品

* 有时使用受控组件会很麻烦，因为你需要为数据变化的每种方式都编写事件处理函数，并通过一个 React 组件传递所有的输入 state。

## 成熟的解决方案

* Formik 是个不错的选择
