表單
在用戶提交表單時,html的默認(rèn)行為會使這個表單跳轉(zhuǎn)到一個新頁面,在React中也是這樣。
在大多數(shù)情況下,我們都會構(gòu)建一個處理提交表單并且可以訪問輸入數(shù)據(jù)的函數(shù),實(shí)現(xiàn)這一點(diǎn)的標(biāo)準(zhǔn)的方法就是使用 “受控組件” 技術(shù)。
1.受控組件
在HTML中,像input,textarea,select,這類表單元素都會維持自身的狀態(tài),并且可以根據(jù)用戶的輸入進(jìn)行更新。
在React中,可變狀態(tài)通常保存在組件的狀態(tài)屬性中,并且只能通過setState()的方法進(jìn)行更新。
我們通過使React變成一個單一的數(shù)據(jù)源來結(jié)合兩者,React負(fù)責(zé)渲染表單的組件和后續(xù)控制表單被輸入時發(fā)生的變化。相應(yīng)的,被React的數(shù)據(jù)控制狀態(tài)的表單組件被稱為 受控組件。
demo
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
})
console.log(event.target.value)
}
handleSubmit(event){
alert('name:'+this.state.value);
event.preventDefault();
}
render(){
return(
<form action="">
<label htmlFor="">
Name:
<input type="text" value={this.state.value} onChange={this.handleChange}/>
</label>
<input type="button" value="Submit" onClick={this.handleSubmit}/>
</form>
)
}
}
ReactDOM.render(
<NameForm />,document.getElementById('root')
)
由于value的值是在表單上設(shè)定的this.state.value,所以顯示的值始終綁定與React的state狀態(tài),并且每次按鍵輸入都會觸發(fā)this.handleChange()來更新React的state,所以展示的值也會一直更新。
使用 “受控組件” 每個狀態(tài)的改變,都有一個與他相關(guān)的處理函數(shù),這樣就能直接修改或者驗(yàn)證用戶的輸入。
例如:限制全部的輸入為 大寫字母
//修改handleChange方法
handleChange(event){
this.setState({
value:event.target.value.toUpperCase()
})
}
2.textarea標(biāo)簽
①在HTML中元素通過他的子節(jié)點(diǎn)來定義它的內(nèi)容
<textarea>hello,React</ textarea>
②在React中,會使用value屬性來代替
class EssayForm extends React.Component{
constructor(props){
super(props);
this.state={
value:'please write an essay'
}
this.handleChange=this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(event){
this.setState({value:event.target.value})
}
handleSubmit(event){
alert('essay:'+this.state.value);
event.preventDefault();
}
render(){
return(
<form onSubmit={this.handleSubmit}>
<label htmlFor="">
Name:
<textarea value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit"/>
</form>
)
}
}
ReactDOM.render(
<EssayForm />,document.getElementById('root')
)
注意this.state.value是在構(gòu)造函數(shù)中初始化,這樣文本區(qū)域就能獲取到其中的文本。
3.select標(biāo)簽
①在HTML中,select會創(chuàng)建一個下拉列表,比如這個HTML就創(chuàng)建了一個下拉列表的原型。
<select>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option selected value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
注意:
Coconut選項(xiàng)上的select由于最初被選中有一個selected屬性,在React中,并不會這樣使用,而是根據(jù)select上的value來顯示選中項(xiàng),這在受控組件中更加方便,因?yàn)槟阒恍枰谝粋€地方修改他的狀態(tài)。
demo
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('choice:'+this.state.value);
event.preventDefault();
}
render(){
return(
<form action="" onSubmit={this.handleSubmit}>
<label htmlFor="">
pick your item
<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>
)
}
}
ReactDOM.render(
<FlavorForm />,document.getElementById('root')
)
總之,<input type="text">,<textarea>, 和 <select> 都十分類似 - 他們都通過傳入一個value屬性來實(shí)現(xiàn)對組件的控制。
4.file input標(biāo)簽
①在HTML中,<input type="file" />允許用戶從他們的存儲設(shè)備中選擇一個或者多個的文件以提交表單的形式提交到服務(wù)器,或者通過 Javascript 的 File API 對文件進(jìn)行操作 。
<input type="file">
由于該標(biāo)簽的 value 屬性是只讀的, 所以它是 React 中的一個非受控組件。我們會把它和其他非受控組件一起在后面的章節(jié)進(jìn)行詳細(xì)的介紹。
5.多個輸入的解決方法
當(dāng)你處理多個受控的input組件時,可以通過給每一個元素添加name屬性,來讓處理函數(shù)event.target.name選擇做些什么。
demo
class Reservation extends React.Component {
constructor(props){
super(props);
this.state={
isGoing:true,
numberOfGuests:200
}
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 //es6語法
})
}
render(){
return(
<form action="">
<label htmlFor="">
is isGoing
<input type="text" name="isGoing" type="checkbox"
checked={this.state.isGoing} onChange={this.handleInputChnage}/>
</label>
<br/>
<label htmlFor="">
number of guests:
<input type="text" name="numberOfGuests" type="number"
value={this.state.numberOfGuests} onChange={this.handleInputChange}/>
</label>
</form>
)
}
}
ReactDOM.render(
<Reservation />,document.getElementById('root')
)
注意我們?nèi)绾问褂肊S6當(dāng)中的計算屬性名語法來更新與給定輸入名稱相對應(yīng)的狀態(tài)鍵:
this.setState({
[name]: value
});
//相當(dāng)于ES5語法如下
var partialState = {};
partialState[name] = value;
this.setState(partialState);
6.受控組件的替代方法
有時使用受控組件可能很繁瑣,因?yàn)槟獮閿?shù)據(jù)可能發(fā)生變化的每一種方式都編寫一個事件處理程序,并通過一個組件來管理全部的狀態(tài)。當(dāng)您將預(yù)先存在的代碼庫轉(zhuǎn)換為React或?qū)eact應(yīng)用程序與非React庫集成時,這可能變得特別煩人。在以上情況下,你或許應(yīng)該看看非受控組件,這是一種表單的替代技術(shù)。