react入門教程二

react事件

由于react的虛擬DOM模式开睡,react對所有的事件也都做了專門的處理和優(yōu)化,官方的說法是引入了虛擬事件對象关串,將瀏覽器的事件進(jìn)行了封裝窃款,有著瀏覽器本地事件西安通的屬性和方法,但是沒有兼容問題框沟。聽起來不錯(cuò)藏古,回到我們之前state的demo,handleClick(e){}加一個(gè)console.log(e)來打印一下這個(gè)點(diǎn)擊事件:

5

這里可以看到我們打印出來的全部是空忍燥,這是因?yàn)閞eact給我們做了處理拧晕,把不需要的值全部隱藏了。現(xiàn)在我們來改一下console.log(e.target) :

6

可以看到target已經(jīng)被打印出來了梅垄。如果你有時(shí)候需要的是本地的event的話可以使用e.nativeEvent來調(diào)用:

7

這里就是瀏覽器原生的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 打印出來來幫助大家更好去理解:

8

這里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)用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市纪挎,隨后出現(xiàn)的幾起案子期贫,更是在濱河造成了極大的恐慌,老刑警劉巖异袄,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件通砍,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)封孙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門迹冤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人虎忌,你說我怎么就攤上這事泡徙。” “怎么了膜蠢?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵堪藐,是天一觀的道長。 經(jīng)常有香客問我挑围,道長礁竞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任杉辙,我火速辦了婚禮模捂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蜘矢。我一直安慰自己狂男,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布品腹。 她就那樣靜靜地躺著岖食,像睡著了一般。 火紅的嫁衣襯著肌膚如雪珍昨。 梳的紋絲不亂的頭發(fā)上县耽,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音镣典,去河邊找鬼。 笑死唾琼,一個(gè)胖子當(dāng)著我的面吹牛兄春,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播锡溯,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼赶舆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了祭饭?” 一聲冷哼從身側(cè)響起芜茵,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎倡蝙,沒想到半個(gè)月后九串,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年猪钮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了品山。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡烤低,死狀恐怖肘交,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情扑馁,我是刑警寧澤涯呻,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站腻要,受9級(jí)特大地震影響魄懂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜闯第,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一市栗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧咳短,春花似錦填帽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至勾效,卻和暖如春嘹悼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背层宫。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來泰國打工杨伙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人萌腿。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓限匣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親毁菱。 傳聞我的和親對象是個(gè)殘疾皇子米死,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • It's a common pattern in React to wrap a component in an ...
    jplyue閱讀 3,267評(píng)論 0 2
  • 深入JSX date:20170412筆記原文其實(shí)JSX是React.createElement(componen...
    gaoer1938閱讀 8,065評(píng)論 2 35
  • 原教程內(nèi)容詳見精益 React 學(xué)習(xí)指南,這只是我在學(xué)習(xí)過程中的一些閱讀筆記贮庞,個(gè)人覺得該教程講解深入淺出峦筒,比目前大...
    leonaxiong閱讀 2,835評(píng)論 1 18
  • 以下內(nèi)容是我在學(xué)習(xí)和研究React時(shí),對React的特性窗慎、重點(diǎn)和注意事項(xiàng)的提取物喷、精練和總結(jié),可以做為React特性...
    科研者閱讀 8,232評(píng)論 2 21
  • 本筆記基于React官方文檔,當(dāng)前React版本號(hào)為15.4.0脯丝。 1. 安裝 1.1 嘗試 開始之前可以先去co...
    Awey閱讀 7,706評(píng)論 14 128