# React表单

表单是应用必不可少的一部分,只要需要用户输入,哪怕是最简单的输入,都离不开表单。

React组件的核心理念就是可预知性和可测试性。给定同样的props和state,任何React组件都会渲染出异样的结果。表单也不例外。

# React两种类型表单组件

在React中,表单组件有两种类型:

  • 约束组件
  • 无约束组件

约束性组件,简单的说,就是由React管理了它的value,而非约束性组件的value就是原生的DOM管理的。

# 无约束表单

非约束性组件这么写:

<input type="text" defaultValue="name" />

这个 defaultValue 其实就是原生DOM中的 value 属性。这样写出的来的组件,其value值就是用户输入的内容,React完全不管理输入的过程。

# 约束性组件

约束性组件是这么写的:

<input type="text" value={this.state.name} onChange={this.handleChange} />

//...省略部分代码
handleChange: function(e) {
  this.setState({name: e.target.value});
}

这里,value属性不再是一个写死的值,他是 this.state.name,而 this.state.name 是由 this.handleChange 负责管理的。 这个时候实际上 input 的 value 根本不是用户输入的内容。而是onChange 事件触发之后,由于 this.setState 导致了一次重新渲染。不过React会优化这个渲染过程,实际它依然是通过设置input的value来实现的。

但是一定要注意,约束性组件显示的值和用户输入的值虽然很多时候是相同的,但他们根本是两码事。约束性组件显示的是 this.state.name 的值。你可以在handleChange中对用户输入的值做任意的处理,比如你可以做错误校验。

示例:输入值转换成大写

class Name extends React.Component{
	constructor(){
    	super();
        this.state = {
        	name:'allcky'
            };
    }
    handleChange(event){
        this.setState({
            name:event.target.value.toUpperCase()
        })
    }
    render(){
        return <input type="text" value={this.state.name} onChange={this.handleChange.bind(this)} />
    }
}

ReactDOM.render(<Name/>,document.querySelector('#app'))

对比约束性组件和非约束性组件的输入流程:

非约束性组件: 用户输入A -> input 中显示A

约束性组件: 用户输入A -> 触发onChange事件 -> handleChange 中设置 state.name = “A” -> 渲染input使他的value变成A

# 表单控件

# Label

Label是表单元素中很重要的组件,通过label可以明确的向用户传达你的要求,提升单选和复选框的可用性。

但是label与for属性有一个冲突的地方。因为如果使用JSX,for 变成了htmlfor 。

# 文本框与Select

React对<textarea/><select/> 的接口做了一些修改,提升了一致性,让他们操作起来更容易。

# textarea

<textarea/>被改的更像<input/>了,允许我们设置value 和defaultValue。

# 非约束的
<textarea defaultValue="hello world" />

# 约束的
<textarea value={this.state.helloTo} onChange={this.handleChange} />

# select

<select/>现在接受value和defaultValue来设置已选项,我们可以更容易地对它的值进行操作。

# 非约束
<select defaultValue="sw">
    <option value="ks">看书</option>
    <option value="wyx">玩游戏</option>
    <option value="dy">电影</option>
</select>

# 约束的
<select value={this.state.fav} onChange={this.handleChange}>
    <option value="ks">看书</option>
    <option value="wyx">玩游戏</option>
    <option value="dy">电影</option>    
</select>

# 复选框和单选框

复选框和单选框使用的则是另外一种完全不同的控制方式。

# 单选框

约束的

var Radio = React.createClass({
  getInitialState: function() {
    return {gender: '男'};
  },
    render: function() {
    return (<div>
          <input type='radio' name='gender' value='男' checked={this.state.sex == '男'} onChange={this.handlerChange} />男
          <input type='radio' name='gender' value='女' checked={this.state.sex == '女'} onChange={this.handlerChange} />女
        </div>);   
  },
  handlerChange: function(event) {
    this.setState({gender: event.target.value});
  }
});

设置单选框的defaultChecked会使其变为无约束组件。

<input type='radio' defaultChecked='true' />

# 复选框

约束的

var CheckBox = React.createClass({
  getInitialState: function() {
    return {basketBall: false, swim: false, sing: false};
  },
  render: function() {
    return (<div>
          <p>爱好:</p>
          <input type='checkbox' checked={this.state.basketBall} value='basketBall' onChange={this.handlerChange} />篮球
          <input type='checkbox' checked={this.state.swim} value='swim' onChange={this.handlerChange} />游泳
          <input type='checkbox' checked={this.state.sing} value='sing' onChange={this.handlerChange} />唱歌
        </div>);   
  },
  handlerChange: function(event) {
    var type = event.target.value,
       checked = event.target.checked,
       newState = {};
    newState[type] = checked;
    this.setState(newState);
  }
});

设置复选框的defaultChecked会使其变为无约束组件。

<input type='checkbox' defaultChecked='true' />

# Focus

控制表单组件的focus可以很好地引导用户按照表单逻辑逐步填写,而且还可以减少用户的操作,增强可用性。

React实现了autoFocus属性,在组件第一次挂载时,如果没有其他表单域聚焦时,React就会把焦点放到这个组件对应的表单域中。

# autoFocus

<input type='text' name='given_name' autoFocus="true" />

# DOM操作方式

var GetName = React.createClass({
    render:function(){
        return (<input type="text" name="given_name" ref="givenName" />)
    },
    componentDidMount:function(){
        var inputName = this.refs.givenName.getDOMNode();
        inputName.focus();
    }
})

# 表单事件

访问表单事件是控制表单不同部分的一个非常重要的方面。

React支持所有HTML事件,这些事件遵循驼峰命名的约定。这些事件是标准化的,提供了跨浏览器的一致接口。

所有的事件都提供了event.target来访问触发事件的DOM节点。

handleEvent:function(event){
    var DOMNode = event.target;
    var newValue = DOMNode.value;
}

这是访问约束组件的值得最简单方式之一。