原文:http://blog.csdn.net/lihongxun945/article/details/46730835
表單是前端非常重要的一塊內容,並且往往包含了錯誤校驗等邏輯。
React對表單元素做了專門的優化處理,他對表單元素做了一些抽象,使得他們的使用方式更統一更規范。
約束性和非約束性組件
表單里面出來了一個新的概念叫“約束性組件”。那么如何理解約束性組件和非約束性組件呢。
約束性組件,簡單的說,就是由react管理了它的value,而非約束性組件的value就是原生的DOM管理的。
他們的寫法上也有很大區別。
非約束性組件這么寫:
<input type="text" defaultValue="a" />
這個 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中對用戶輸入的值做任意的處理,比如你可以做錯誤校驗。
對比約束性組件和非約束性組件的輸入流程:
- 非約束性組件: 用戶輸入A -> input 中顯示A
- 約束性組件: 用戶輸入A -> 觸發onChange事件 -> handleChange 中設置 state.name = “A” -> 渲染input使他的value變成A
正式因為這樣,強烈推薦使用約束性組件,因為它能更好的控制組件的生命流程。
更統一和更規范的接口
React 把 input,textarea 和 select 三個組件做了抽象和封裝,他們的用法變得非常統一,你基本上可以當做同一個組件來用。
他們現在有統一的 value 屬性 和 onChange 事件,現在對於這三種組件你都可以這樣寫
<input type='text' name='intro' id='intro' value={this.state.email} onChange={this.handleEmail} />
<textarea type='text' name='intro' id='intro' value={this.state.intro} onChange={this.handleIntro} />
<textarea type='text' name='intro' id='intro' value={this.state.intro} onChange={this.handleIntro} />
不過 chekbox有和上面三個不一樣,因為checkbox改變的不是 value ,而是 checked 狀態。
你可以這樣寫:
<input type='radio' name='gender' checked={this.state.male} onChange={this.handleGender} value='MALE' />
<input type='radio' name='gender' checked={!this.state.male} onChange={this.handleGender} value='FEMALE' />
一個示例
下面是一個包含了 input,textarea, select, radio 的表單,並且做了簡單的校驗:
var MyForm = React.createClass({
getInitialState: function() {
return {
email: "",
intro: "",
city: "hz",
male: true, //性別
emailError: "",
introError: ""
};
},
handleEmail: function(e) {
var value = e.target.value;
var error = '';
if(!(/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(value))) {
error = '請輸入正確的Email';
}
this.setState({
email: value,
emailError: error
});
},
handleIntro: function(e) {
var value = e.target.value;
var error = "";
if(value.length < 10) {
error = "介紹不能少於十個字";
}
this.setState({
intro: value,
introError: error
});
},
handleCity: function(e) {
var value = e.target.value;
this.setState({
city: value,
});
},
handleGender: function(e) {
var male = !!(e.target.value == 'MALE');
this.setState({
male: male
});
},
render: function() {
return (
<div>
<p>
<label htmlFor='email'>email:</label>
<input type='text' name='intro' id='intro' value={this.state.email} onChange={this.handleEmail} />
<span>{this.state.emailError}</span>
</p>
<p>
<label htmlFor='intro'>intro:</label>
<textarea type='text' name='intro' id='intro' value={this.state.intro} onChange={this.handleIntro} />
<span>{this.state.introError}</span>
</p>
<p>
<label htmlFor='city'>所在城市:</label>
<select name='city' id='city' value={this.state.city} onChange={this.handleCity}>
<option value='hz'>杭州</option>
<option value='bj'>北京</option>
<option value='sh'>上海</option>
</select>
</p>
<p>
<label>性別:</label>
<input type='radio' name='gender' checked={this.state.male} onChange={this.handleGender} value='MALE' />
<input type='radio' name='gender' checked={!this.state.male} onChange={this.handleGender} value='FEMALE' />
</p>
</div>
)
}
});
React.render(
<MyForm />,
document.getElementById("div1")
);