## 一、表单(Forms)
> HTML 表单元素与 React 中的其他 DOM 元素有所不同,因为表单元素自然地保留了一些内部状态。例如,这个纯 HTML 表单接受一个单独的 name
### 1.1 受控组件
> 在 HTML 中,表单元素如 \<input\>,\<textarea\> 和 \<select\> 表单元素通常保持自己的状态,并根据用户输入进行更新。而在 React 中,可变状态一般保存在组件的 state(状态) 属性中,并且只能通过 setState() 更新。
```
<input
type="text"
value={this.state.value}
onChange={(e) => {
this.setState({
value: e.target.value.toUpperCase(),
});
}}
/>
```
> 如上:在React中 的表单元素input,绑定了change事件,其value值与组件state属性相关联,每当表单的状态发生变化,都会被写入组件的state中,这种组件叫 **受控组件**
> 从形式上看,受控组件即绑定有**value值**的组件(且需要有onChange事件响应函数对应当value值变化时的处理),非受控组件就是没有绑定value值的组件
```
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) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
```
- 受控组件两要素:value,onChange
### 1.2 textarea标签
> 在 React 中,\<textarea\> 的赋值使用 **value 属性**替代。这样一来,表单中 \<textarea\> 的书写方式接近于单行文本输入框
```
class EssayForm extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 'Please write an essay about your favorite DOM element.'
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('An essay was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<textarea value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
```
- 注意,this.state.value 在构造函数中初始化,所以这些文本一开始就出现在文本域中。
### 1.3 select标签
- select标签的值由 **value**指定,而不是使用selected属性
- onChange事件绑定 当select对应的state变化时的操作函数
```
class FlavorForm extends React.Component {
constructor(props) {
super(props);
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) {
alert('Your favorite flavor is: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<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>
<input type="submit" value="Submit" />
</form>
);
}
}
```
- 您可以将一个数组传递给 value 属性,允许你在 select 标签中选择多个选项:
```
selectChange(e) {
let val = e.target.value;
this.setState(prev=>{
const prevLike = prev.like;
console.log(val)
if (prevLike.indexOf(val) == -1) {
prevLike.push(val)
} else {
prevLike.forEach((item,index) => {
if (item == val) {
prevLike.splice(index,1)
return;
}
})
}
return { like: prevLike }
})
}
render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<div>name: <input type="text" value={this.state.name} onChange={(e) => this.setState({ name: e.target.value })} /></div>
<div>like:
<select multiple='multiple' value={this.state.like} onChange={this.selectChange.bind(this)}>
<option value="orange">orange</option>
<option value="pear">pear</option>
<option value="Apple">Apple</option>
<option value="melon">melon</option>
</select>
</div>
<input type='submit' value='submit'/>
<div>
show:{this.state.name} like {this.state.like}
</div>
</form>
)
}
```
### 1.4 表单多元素处理
>当需要处理多个受控的input元素时,可以为元素添加name属性,并让处理函数根据event.target.name的值来选择要做什么
```
handleChange(e) {
var target = e.target,
name = target.name,
val = target.type==='checkbox'||target.type==='radio'?target.checked:target.value;
this.setState({
[name]:val
})
}
render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<div>name: <input name="name" type="text" value={this.state.name} onChange={this.handleChange.bind(this)} /></div>
<div>password:<input name="pwd" type='password' value={this.state.pwd} onChange={this.handleChange.bind(this)}/></div>
<input type='submit' value='submit'/>
<div>
show:{this.state.name} like {this.state.like}
</div>
</form>
)
}
```
- 注意:此处用到了ES6的[计算属性名](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Object_initializer)\[name\]来表示对应的state值
### 受控组件缺点
- 有时使用受控组件有些乏味,因为你需要*为每一个可更改的数据提供事件处理器*,并*通过 React 组件管理所有输入状态*。
- 在受控组件中,表单数据由React组件负责处理。而在非受控组件中,表单数据由DOM元素本身处理。
- 性能问题:在受控组件中,每次表单的值发生变化都会调用onChange事件处理器,这确实会带来性能上的损耗(这个问题可以通过Flux/Redux应用架构等方式来达到统一组件状态的目的)
## 二、非受控组件
> 在表单组件中,没有value属性(单复先没有checked属性)时,可以称之为非受控组件。
- 使用defaultValue和defaultChecked来表示组件的默认状态;
- 通过 defaultValue和defaultChecked来设置组件的默认值,它仅会被渲染一次,在后续的渲染时并不起作用
```
handleSubmit(e) {
e.preventDefault();
const nameInput = this.nameInput.value,
pwdInput = this.pwdInput.value;
console.log(nameInput,pwdInput)
}
render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<div>name: <input name="name" type="text" defaultValue="admin" ref={i=>this.nameInput=i}/></div>
<div>password:<input name="pwd" type='password' ref={i=>this.pwdInput=i}/></div>
<input type='submit' value='submit'/>
</form>
)
}
```
- defaultValue或defaultChecked来设置默认值
- ref为一个接受DOM元素作为参数的回调函数,在其中可以将DOM元素映射到组件中再取值
- 一、安装与使用
- 二、JSX介绍
- 三、React渲染
- 四、组件Components
- 4.1 定义组件
- 4.2 复合组件
- 4.3 React创建组件的三种方式及其区别
- 五、Props(属性)和State(状态)
- 5.1 Props属性
- 5.2 State状态
- 5.3 组件间的通信
- 5.4 单向数据流&事件
- 5.5 Refs属性
- 六、React生命周期
- 七、React组件应用场景
- 7.1 条件渲染
- 7.2 列表渲染和Key
- 7.3 表单组件
- 八、React-router初识
- 8.1 React-router主要组件
- 九、项目中的问题记录
- 9.1 antd+react项目初体验
- 9.2 fetch请求
- 9.3 简单项目的规范
- 十、redux简介&使用
- 10.1 基本概念和API
- 10.0 踩坑记录
- 10.2 react-redux