react事件
由于react的虛擬DOM模式开睡,react對所有的事件也都做了專門的處理和優(yōu)化,官方的說法是引入了虛擬事件對象关串,將瀏覽器的事件進(jìn)行了封裝窃款,有著瀏覽器本地事件西安通的屬性和方法,但是沒有兼容問題框沟。聽起來不錯(cuò)藏古,回到我們之前state的demo,handleClick(e){}
加一個(gè)console.log(e)
來打印一下這個(gè)點(diǎn)擊事件:
這里可以看到我們打印出來的全部是空忍燥,這是因?yàn)閞eact給我們做了處理拧晕,把不需要的值全部隱藏了。現(xiàn)在我們來改一下console.log(e.target)
:
可以看到target已經(jīng)被打印出來了梅垄。如果你有時(shí)候需要的是本地的event的話可以使用e.nativeEvent來調(diào)用:
這里就是瀏覽器原生的event事件厂捞,但是需要注重瀏覽器兼容性。所以一般情況下最好使用react封裝好的event事件队丝,react支持的完整事件列表可以在官方文檔查看靡馁,這里不再一一列舉。
tip:如果需要阻止默認(rèn)的事件机久,比如form表單的默認(rèn)提交臭墨,a標(biāo)簽的href... 必須使用e.preventDefault() 。而需要阻止事件冒泡則需使用e.stopPropagation()吞加。
React事件機(jī)制不同于我們以往的js事件裙犹,為提高效率尽狠,它對事件做了二次處理,將所有項(xiàng)目中注冊的事件全部代理(delegate)到頂層的document上叶圃,當(dāng)你點(diǎn)擊某個(gè)DOM的時(shí)候袄膏,它會(huì)找到這個(gè)DOM和其Component,并冒泡到找到對應(yīng)的事件并觸發(fā)掺冠。
比如我們經(jīng)典的 ul li 結(jié)構(gòu)沉馆,傳統(tǒng)js使用事件委托將事件綁定在ul上,而現(xiàn)在使用react只需要在ul上綁一個(gè)click事件德崭,每次點(diǎn)擊ul里面的元素都會(huì)冒泡并觸發(fā)到ul的事件上去斥黑。但是要注意如果你在ul里面再綁定一個(gè)事件,同時(shí)不使用stopPropagation去阻止這個(gè)冒泡事件眉厨,那他會(huì)一直執(zhí)行到最頂層的事件上去锌奴。
想要深入了解React事件機(jī)制?相信這篇博客會(huì)對你有所幫助——React源碼解讀系列 -- 事件機(jī)制
Refs & 真實(shí)DOM
由于react使用虛擬DOM的結(jié)構(gòu)憾股,所有的頁面變動(dòng)都先在虛擬DOM上處理鹿蜀,只有當(dāng)他們真正插入到文檔中才會(huì)轉(zhuǎn)化成真實(shí)DOM,react正是通過這樣的機(jī)制來減少DOM操作從而提高頁面的性能服球。
但是有時(shí)候我們確實(shí)有獲取DOM的需求茴恰,前面在學(xué)習(xí)事件的時(shí)候我們使用e.target可以獲取到真實(shí)的DOM。
而同時(shí)react也給我們提供了refs 來處理類似的情況斩熊。ref在react中是一個(gè)特殊的屬性往枣,它可以是一個(gè)回調(diào)函數(shù)也可以是一個(gè)字符串。如果你查找國內(nèi)的資料你會(huì)發(fā)現(xiàn)幾乎所有人用的都是ref的字符串屬性粉渠,但是在最新版(V15.4.2)的react文檔中分冈,ref的字符串屬性被稱為’Legacy API‘ ,官方強(qiáng)調(diào)字符串的ref存在一些問題渣叛,并且很可能在未來的版本中將其移除丈秩。
我們先來看一下官方的demo:
var MyComponent = React.createClass({
handleClick: function() {
this.textInput.focus();
console.log(this);
console.log(this.textInput)
},
render: function() {
return (
<div>
<input type="text" ref={(input) => { this.textInput = input; }} />
<input type="button" value="Focus the text input" onClick={this.handleClick} />
</div>
);
}
});
ReactDOM.render(
<MyComponent />,
document.getElementById('example')
);
ref的回調(diào)函數(shù)會(huì)在組件創(chuàng)建或者重新渲染時(shí)立即執(zhí)行,回調(diào)函數(shù)的參數(shù)即為當(dāng)前組件的真實(shí)DOM淳衙,我們可以立即使用這個(gè)DOM或者將其保存以備后用蘑秽。
上面代碼中輸入框的ref使用es6語法直接在組件中創(chuàng)建了一個(gè)回調(diào)函數(shù),這個(gè)函數(shù)將參數(shù)input保存到this.textInput中箫攀,我這里把 this 和 this.textInput 打印出來來幫助大家更好去理解:
這里this指向ReactElement肠牲,即當(dāng)前的的react組件,通過回調(diào)函數(shù)往this里添加了textInput對象靴跛。通過下面的this.textInput就可以看到textInput為該組件的原生DOM缀雳,我們通過ref的回調(diào)函數(shù)將該DOM存在this中,方便后面隨時(shí)調(diào)用梢睛。
簡單的ref回調(diào)我們可以直接寫在標(biāo)簽中肥印,如果復(fù)雜的話我們可以將其抽出為一個(gè)函數(shù)识椰,在標(biāo)簽中通過 ref={this.funtionName}
的形式調(diào)用。
同時(shí)我這里也有一個(gè)string refs的demo,雖然現(xiàn)在有很多人這樣用,但是我們要盡量避免這樣的寫法:
var MyComponent = React.createClass({
handleClick: function() {
this.refs.myTextInput.focus();
},
render: function() {
return (
<div>
<input type="text" ref="myTextInput" />
<input type="button" value="Focus the text input" onClick={this.handleClick} />
</div>
);
}
});
ReactDOM.render(
<MyComponent />,
document.getElementById('example')
);
這里給ref定義一個(gè)字符串枷畏,通過refs獲取到頁面所有的ref,再通過ref的字符串定位到該DOM功咒,這樣操作確實(shí)方便很多,所以這個(gè)方法被廣為流傳绞蹦,但是建議有使用這樣方法的童鞋最好慢慢拋棄這種寫法力奋。
tips:有些童鞋可能網(wǎng)上查找資料會(huì)看到getDOMNode() or findDOMNode() 方法,在早期react中確實(shí)存在這些方法結(jié)合ref來獲取DOM幽七,但是后來React拆分出ReactDOM后這些方法被歸到ReactDOM 的方法中景殷,直接在react中是不能使用的。
react表單
在開始之前我們先看一個(gè)例子:
var Form = React.createClass({
render: function() {
return (
<input type='text' value='這是一個(gè)輸入框'/>
)
}
})
ReactDOM.render(
<Form/>,
document.getElementById('example')
);
乍一看是不是和我們平時(shí)HTML的寫法基本一樣锉走,但是一運(yùn)行你就會(huì)發(fā)現(xiàn)無論如何你改變不了input中的值滨彻,鍵盤的輸入對它沒有任何影響藕届!
react官方將帶有value的表單定義為受限組件 挪蹭,即該組件受限制于value值,他將永遠(yuǎn)等于value的值休偶。當(dāng)然梁厉,不代表我們就不能定義表單的默認(rèn)值了,官方給出了兩種解決辦法:
1踏兜,使用defaultValue词顾。既然有受限組件,那就存在不受限組件碱妆。官方定義為不設(shè)置value的組件就是一個(gè)不受限組件肉盹,而不受限組件可以實(shí)時(shí)響應(yīng)用戶的輸入將其反映到元素上。所以react就給組件定義了defaultValue來給組件設(shè)置一個(gè)非空的初始值疹尾,而對于radio上忍,checkbox則有對應(yīng)的defaultCheckd屬性來代替checkd:
<input type='text' defaultValue='這里是默認(rèn)值,也可以使用state'/>
我們可以給input定義ref的回調(diào)來獲取輸入的值:
<input type='text' ref={(input) => { this.textInput = input; }} defaultValue='這里是默認(rèn)值纳本,也可以使用state'/>
然后通過事件獲取this.textInput.value窍蓝。
比如我們一個(gè)頁面有很多輸入框,可以給他們分別定義ref繁成,然后通過submit按鈕的提交事件來一次性全部獲取所有的輸入值吓笙。
tip:如果我們需要阻止默認(rèn)的表單提交事件,需要使用e.preventDefault()巾腕,這一點(diǎn)我們在之前的事件里提到過面睛。 ( ) => { }
為ES6語法絮蒿,它表示為 function( ) { }
。
2叁鉴,對于使用state來給組件設(shè)置初始值的歌径,可以給組件綁定onChange事件,通過onChange來實(shí)時(shí)獲取用戶輸入亲茅,動(dòng)態(tài)的改變state的值回铛。這樣雖然組件受限于value,但是value的值發(fā)生了變化克锣,那么組件的值也就跟著變化:
var Form = React.createClass({
getInitialState:function(){
return {
inputValue: 'input',
}
},
handleInput:function(e) {
this.setState({inputValue: e.target.value});
},
render: function() {
return (
<input type='text' value={this.state.inputValue} onChange={this.handleInput}/>
)
}
})
ReactDOM.render(
<Form/>,
document.getElementById('example')
);
以上是使用e.target.value來獲取輸入值來刷新state茵肃,當(dāng)然你也可以使用ref來獲取。
如果頁面中有很多表單袭祟,但是我們又不想使用上面的defaultValue+ref验残,或者我們需要在用戶輸入的時(shí)候就獲取輸入值來檢查。豈不是每一個(gè)表單組件都要定義一個(gè)onChange事件巾乳?
官方也考慮到這種問題您没,所以給我們提供了一個(gè)更好的解決方案:
var MyComponent = React.createClass({
getInitialState: function() {
return {
isGoing: true,
numberOfGuests: 2
};
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
});
},
render: function() {
return (
<form>
<label>
Is going:
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
</label>
<br />
<label>
Number of guests:
<input
name="numberOfGuests"
type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</label>
</form>
);
}
});
ReactDOM.render(
<MyComponent />,
document.getElementById('example')
);
通過一個(gè)onChange事件來解決所有的表單,是不是很酷胆绊!
tip: [name]
為ES6語法氨鹏,它表示在對象中,name為一個(gè)變量压状。
tip:<textarea>
常規(guī)設(shè)置默認(rèn)值采用 <textarea>這里是默認(rèn)值</textarea>
仆抵,<select>
常規(guī)設(shè)置默認(rèn)值是在 <option>
中添加selected,而這對于React來說會(huì)顯得很奇怪种冬,且不方便在后續(xù)的使用中來更新默認(rèn)值镣丑。所以React中所有表單的默認(rèn)值設(shè)置全部使用value(defaultValue)來定義,詳細(xì)說明參見官方文檔娱两。
生命周期
組件的生命周期分為三種:
- Mounting:已插入真實(shí) DOM
- Updating:正在被重新渲染
- Unmounting:已移出真實(shí) DOM
react為每個(gè)狀態(tài)提供兩種處理函數(shù)莺匠,will在函數(shù)狀態(tài)之前調(diào)用,did則在函數(shù)狀態(tài)之后調(diào)用:
- componentWillMount()
- componentDidMount()
- componentWillUpdate(object nextProps, object nextState)
- componentDidUpdate(object prevProps, object prevState)
- componentWillUnmount()
此外還有三種特殊狀態(tài)的處理函數(shù):
- constructor():組件調(diào)用之前的構(gòu)造函數(shù)十兢,早于componentWillMount()趣竣,常用于聲明props和state
- componentWillReceiveProps(object nextProps):已加載組件收到新的參數(shù)時(shí)調(diào)用
- shouldComponentUpdate(object nextProps, object nextState):組件判斷是否重新渲染時(shí)調(diào)用