表單(一)
受控 && 非受控元件
在react中,提出了受控與非受控元件,對比我們之前的做法,非受控元件就相當於我們之前的版本,沒有預設值,或者一般將初始狀態進行設定,而受控元件指的是為其指定預設值以及為事件繫結與控制元件對應的值。
- 案例程式碼連結
import React from "react";
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
value: "color"
};
}
handleChange(e) {
this.setState({
value: e.target.value
});
}
render() {
const { value } = this.state;
return (
<div class="app">
<h2>form受控元件</h2>
<input defaultValue={value} onChange={this.handleChange.bind(this)} />
<h2>form非受控元件</h2>
<input name="username" />
</div>
);
}
}
export default Form;
複製程式碼
在react建議中,一般都建議我們寫受控元件,這樣應用的狀態以及資料可以實時把握,並根據需要進行渲染。
select 與 checkbox等預設值的設定
另外一點不得不提的是一些表單控制元件的預設值的設定,在傳統的控制元件寫法中我們是直接將選中項的值設定為checked,selected,而在react中,我們是通過設定其父標籤,也就是select標籤的值來實現的。
並且這種思想無論在react元件還是vue元件中都很常見,也不侷限於表單元件,我們習慣了將一個容器內包含著若干元素的元件的預設值通過配置容器屬性來實現,而不是每個具體元件設定值。
<select>
<option value="男">男</option>
<option value="男" selected>女</option>
</select>
<select value='女'>
<option value="男">男</option>
<option value="女">女</option>
</select>
複製程式碼
其實你如果是上面的這種寫法,說明你還沒有完全從傳統的寫法中脫離出來,結合react的設計思想,我們應該把一切符合資料概念的資料放到狀態state裡去管理。有了這種思想,我們才能更好的用好這個框架。
// 構造器
constructor(props){
super(props);
this.state = {
sexArr :[{
value:'0',
label:'男'
},{
value:'1',
label:'女'
}
],
value:'0'
}
}
render(){
let {sexArr, value} = this.state;
return(
<select value={value}>
{sexArr.map(item=>(<option key={item.value} value={item.value}>{item.label}</option>))}
</select>
)
}
複製程式碼
受控元件是為什麼?資料改造還是獲取數值
可能通過受控元件我們發現文字的獲取值以及設定值比原先複雜多了,因為原先的方式,非受控的時候,我們就可以直接改變數值,獲取的時候直接獲取就可以了,加了受控反而增加很多累贅的程式碼,這裡進行下說明。
增加了事件監聽並沒有增加更多的程式碼
我們在每個表單元件中增加了事件監聽,讓其事件改變後的值賦值到我們的狀態機,而且是必須這樣操作,這個目的是為了讓資料直接儲存到我們的狀態機裡,然後進行統一的讀取方便其他需要時呼叫。
這裡對比下我們之前的開發方式,比如說jq框架下,我們雖然不用寫時間監聽改變值,但沒有統一管理變數的思想時,我們總是每次用到數值的時候都需要寫獲取元素,然後獲取元素的值,這部分的程式碼我們現在不需要了。
所以這裡與原來的方式對比可以理解為下面幾點重要的區別:
- 增加了事件監聽,多寫了很多事件監聽函式,原先不用寫
- 增加了state值的賦值,方便了需要時方便的讀取,原先不用寫
- 方便了資料的獲取,需要時統一通過解構從state中直接獲取,原先需要獲取元素獲取屬性值
- 方便了資料的統一管理,原先是沒有統一管理,資料管理比較亂
- 減少了反覆根據需要設定控制元件的選中情況,原先需要根據需求不斷的進行手動改變控制元件的值
增加了資料改造的入口
通過顯性的增加事件監聽,我們可以根據需求靈活的對資料進行驗證或者資料改造,在應用日益複雜的今天,這方面的需求還是非常多的,我們獲取資料不僅僅是為了獲取資料,或者說不僅僅是直接使用這個資料,也可能是需要改造這個資料,或者基於這個資料去生成其他資料,或者執行其他函式,變為受控元件給了我們有這些需求時方便操作的時機和入口和設計方案。
事件繫結的效能優化
雖然受控元件意味著增加很多的事件監聽,但這仍然是react推薦的方式,我們可以通過以下的方式簡化這個認為複雜的過程。
redux/flux
這兩個資料共享的技術方案可以很方便的解決這個問題,將資料進行額外的管理,這裡不做更多介紹。
事件繫結直接優化
其實基於事件繫結,很多人認為繁瑣,或者說就是繁,還是因為對函式的提煉思維不夠,我們針對事件的繫結需要儘可能的抽象,不要針對每一個具體的元件去繫結事件寫具體函式,而要儘可能的抽象,尤其對於同一類事件型別。下面程式碼說明。
class Form extends React.component{
constructor(props){
super(props);
this.state = {
inputValue:'',
sex:1,
sexArr :[{
value:'0',
label:'男'
},{
value:'1',
label:'女'
}
],
}}
handleInputChange(e){
this.setState({
inputValue:e.target.value
})
}
handleSexChange(e){
this.setState({
inputValue:e.target.value
})
},
render(){
let {sexArr, sex,inputValue} = this.state;
return(
<div>
<input value={inputValue} onChange={this.handleInputChange.bind(this)} name="name">
<select value={sex} onChange={this.handleSexChange.bind(this)} name="sex">
{sexArr.map(item=>(<option key={item.value} value={item.value} name="sex">
{item.label}</option>))}
</select>
</div>
)
}
}
複製程式碼
觀察發現,兩者監聽的同一類事件,並且賦值也是類似的,那麼我們直接增加事件監聽的通用性即可,減少事件監聽與具體改變值的耦合。(下面只提供變動的程式碼)
handleChange(type,e){
const {value} = e.target;
this.setState({
[type]:value
})
render(){
let {sexArr, sex,inputValue} = this.state;
return(
<div>
<input value={inputValue} onChange={this.handleChange.bind(this,'inputValue')} name="name">
<select value={sex} onChange={this.handleChange.bind(this,'sex')} name="sex">
{sexArr.map(item=>(<option key={item.value} value={item.value} name="sex">
{item.label}</option>))}
</select>
</div>
)
}
複製程式碼