了解一個React組件

最近React,這個專注View層的庫格外火熱刻肄,我個人已經(jīng)探索了一段時間吻氧,本來一直想寫一些文字溺忧,總結(jié)下React應(yīng)用開發(fā)和webpack構(gòu)建工具的經(jīng)驗(yàn)。不過懶癌復(fù)發(fā)盯孙,一直沒動筆鲁森。前段時間給團(tuán)隊安利這個庫,現(xiàn)在要開始用它寫項目了振惰,所以自己挖的坑要填上歌溉,就開始寫一些基本的東西,就先從介紹React組件的基礎(chǔ)開始骑晶。


從一個簡單的組件開始

標(biāo)題叫“一個簡單的組件”痛垛,于是先來看下官方網(wǎng)站上一個叫做“A Simple Component”的例子來感受下:

var HelloMessage = React.createClass({
  render: function() {
    return <div>Hello {this.props.name}</div>
  }
})
React.render(<HelloMessage name="John" />, mountNode)

好的,通過React提供的工廠方法桶蛔,我們創(chuàng)建了一個組件匙头,在這里,我們認(rèn)為createClass創(chuàng)建了一張blueprint羽圃,而通過jsx語法創(chuàng)建的<HelloMessage name="John" />則返回一個ReactElement對象來具體地告訴React要如何渲染組件(因?yàn)槌薭lueprint以外還需要一些外部狀態(tài)的傳入)乾胶,這等同于調(diào)用React.createElement(HelloMessage, { name: 'John' }, 'Hello ', this.props.name)

之后朽寞,React就可以根據(jù)ReactElement對象识窿,把組件掛載到頁面的某個節(jié)點(diǎn)上去,也就是React.render方法在做的事情脑融,這個方法返回一個組件的實(shí)例喻频,同時也意味著你可以在已有項目中的一小部分嘗試React。

下面來具體介紹下肘迎。

JSX

上面的例子里看著像是把HTML寫在了Js里甥温,實(shí)際上是通過一種更加清晰易讀且易維護(hù)的語法JSX來創(chuàng)建ReactElement對象锻煌。對React來說JSX是可選的,如果真的不喜歡也可以用React.createElement這個api姻蚓。

當(dāng)然有JSX語法的js文件是不能直接在瀏覽器中運(yùn)行的宋梧,我們可以用官方的JSXTransformer或者是babel來轉(zhuǎn)換。

需要注意的是classfor這兩個HTML屬性狰挡,由于組件的屬性實(shí)際是以對象形式傳遞的捂龄,比如上面的{ name: 'John' },另外js不允許關(guān)鍵字作為屬性名加叁,所以需要分別用classNamehtmlFor代替倦沧。

創(chuàng)建一個組件

創(chuàng)建組件的時候需要給React.createClass提供一個對象,這個對象必須包含一個render方法和若干可選的生命周期方法它匕。

要注意的是我們需要保證render函數(shù)是純函數(shù)展融,即同樣的輸入始終返回相同的輸出,并且執(zhí)行過程中沒有副作用(和DOM交互或者發(fā)Ajax請求)豫柬。但一個組件要和DOM交互或者發(fā)Ajax請求需求是很正常的告希,那么就要用到其他生命周期方法了。

除此之外烧给,更重要的部分是暂雹,讓一個組件可以工作除了有blueprint外,還需要組件狀態(tài)创夜。對于一個React組件來說,分為不可變狀態(tài)this.props和可變狀態(tài)this.states仙逻。

我們可以通過this.props決定一個組件內(nèi)的部分呈現(xiàn)內(nèi)容驰吓,比如上例中我們希望呈現(xiàn)的名字是John,且不會改變系奉。然而對于一個DropDownList而言檬贰,僅在點(diǎn)擊它時,一個下拉列表才會顯示出來缺亮,那么我們認(rèn)為這個下拉列表是否顯示就是一個可變狀態(tài)翁涤。

說到可變狀態(tài),那么要這么變萌踱?React并不希望我們直接修改this.states葵礼,我們需要使用this.setState的方式修改狀態(tài),因?yàn)槊看握{(diào)用this.setState并鸵,render方法都會被再次調(diào)用鸳粉,同時也會調(diào)用一些相關(guān)的生命周期函數(shù)。this.setState接受一個對象作為新狀態(tài)的patch园担,也就是說這個對象不會覆蓋現(xiàn)有的this.states届谈,而是一個類似extend的行為枯夜。

我們也可以提供一些默認(rèn)狀態(tài):

getDefaultProps () {
  return {
    name: 'defaultName'
  };
},
getInitialState: function() {
  return {
    listShowed: false
  };
},

其中getDefaultProps僅會被調(diào)用一次,這里的意思是無論你會創(chuàng)建多少個ReactElement艰山,這個函數(shù)都只執(zhí)行一次湖雹,之后的默認(rèn)props都會直接使用改函數(shù)的返回值。

這里需要提一下React提供以ES6的方式創(chuàng)建組件曙搬,有意思的是ES6的版本用的是React.Component摔吏,在語意上比createClass更加明確。getDefaultPropsgetInitialState在ES6的版本中有些不太一樣织鲸,相對與getDefaultProps舔腾,ES6將默認(rèn)屬性對象作為了構(gòu)造函數(shù)的一個屬性,而getInitialState則變成了在其構(gòu)造器函數(shù)中給this.state賦值搂擦,來看一個栗子:

class HelloMessage extends React.Component {
  constructor (props, context) {
    super(props, context)

    this.state = {  } // 初始化狀態(tài)
  }
  render () {
    return <div>Hello {this.props.name}</div>
  }
}
HelloMessage.defaultProps = { name: 'defaultName' }

組件的生命周期

之前的部分一直有提到生命周期函數(shù)稳诚,下面就來介紹下:

componentWillMount會在組件即將被掛載時調(diào)用,此時this.refs對象為空對象瀑踢。如果在該函數(shù)中使用this.setState扳还,那么會更新this.states對象,而render依然只會調(diào)用一次橱夭,相當(dāng)于是可以覆蓋getInitialState返回的對象氨距,雖然我覺得這沒什么意義。

componentDidMount是非常常用的生命周期方法棘劣,僅當(dāng)組件被掛載后調(diào)用一次俏让,這意味著可以在這個函數(shù)中進(jìn)行一些DOM操作等,比如希望組件中的一個textbox可以再掛載后自動獲取焦點(diǎn):

componentDidMount () {
  const textbox = React.findDOMNode(this.refs.text)
  if (this.props.autoFocus) textbox.focus()
}

componentWillReceiveProps在將要接受新的props時被調(diào)用茬暇,不是說props是不可變狀態(tài)嗎首昔?情況通常是這樣的,當(dāng)一個父組件包含了一個子組件糙俗,子組件的一個props的值是父組件的states的值勒奇,那么當(dāng)父組件可變狀態(tài)改變時,子組件的props也更新了巧骚,于是調(diào)用了這個函數(shù)赊颠。

componentWillReceiveProps (nextProps) {
  if (this.props.disabled !== nextProps.disabled) {
    // disabled這個屬性改變了
  }
}

這個生命周期函數(shù)componentWillReceiveProps提供了更新states的機(jī)會,可以調(diào)用this.setState劈彪,也是唯一可以在組件更新周期中調(diào)用this.setState的函數(shù)竣蹦。

shouldComponentUpdate是在更新前根據(jù)該函數(shù)的返回值決定是否進(jìn)行這次更新。

shouldComponentUpdate (nextProps, nextState) {
    // 比較props或者states沧奴,返回true則更新照常草添,返回false則取消更新,且不會調(diào)用下面的兩個生命周期函數(shù)
}

考慮這種情況:父組件有子組件A和子組件B扼仲,當(dāng)父組件調(diào)用this.setState更新一個作為子組件A屬性的state時远寸,render方法被再次調(diào)用抄淑,此時組件A和組件B同時被更新,其實(shí)真正改變的只有組件A驰后,但組件B也同時被要求更新了肆资,這是沒有必要的,于是shouldComponentUpdate就顯的有用了灶芝,在該函數(shù)體內(nèi)比較props或是states郑原,如果沒有改變就取消這個更新,這對性能上算是一個提升夜涕。

但如果是復(fù)雜對象的比較就比較麻煩了犯犁,因?yàn)槲覀儫o法通過===來判斷兩個對象的鍵值是否都相等,于是我們就希望我們的對象是不可變的(immutable)女器。這里不再展開了酸役,大家可以先自行探索,之后再寫這個部分的文字驾胆,并介紹immutable.js

componentWillUpdate在組件被更新前調(diào)用一次涣澡,可以用來做一些更新前的準(zhǔn)備工作,舉個栗子:

componentWillUpdate (nextProps, nextState) {
  if (!this.props.isShowed && nextProps.isShowed) {
    // 比如下拉菜單此時變的顯示了丧诺,可以對此監(jiān)聽一些事件什么的
  }

  if (this.props.isShowed && !nextProps.isShowed) {
    // 比如下拉菜單隱藏了入桂,可以在這里取消事件監(jiān)聽
  }
}

(組件更新前事情還蠻多的...)

componentDidUpdate在組件更新完成后調(diào)用,可以考慮在這個函數(shù)中執(zhí)行一些DOM操作什么的驳阎。

注意:絕對不要在componentWillUpdatecomponentDidUpdate中調(diào)用this.setState方法抗愁,否則將導(dǎo)致無限循環(huán)調(diào)用。

componentWillUnmount會在組件即將從掛載點(diǎn)移去時調(diào)用呵晚,此方法專門用來『擦屁股』驹愚,比如去除即將被銷毀的DOM節(jié)點(diǎn)的引用,或者是清除計時器劣纲,取消監(jiān)聽的時間等等。


好了谁鳍,正文結(jié)束癞季,這一篇介紹了React比較基礎(chǔ)的部分,希望對大家有幫助倘潜,之后還會有一些更有針對性的部分绷柒。如文章中內(nèi)容有誤,還請指正涮因。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末废睦,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子养泡,更是在濱河造成了極大的恐慌嗜湃,老刑警劉巖奈应,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異购披,居然都是意外死亡杖挣,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門刚陡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惩妇,“玉大人,你說我怎么就攤上這事筐乳「柩辏” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵蝙云,是天一觀的道長氓皱。 經(jīng)常有香客問我,道長贮懈,這世上最難降的妖魔是什么匀泊? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮朵你,結(jié)果婚禮上各聘,老公的妹妹穿的比我還像新娘。我一直安慰自己抡医,他們只是感情好躲因,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著忌傻,像睡著了一般大脉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上水孩,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天镰矿,我揣著相機(jī)與錄音,去河邊找鬼俘种。 笑死秤标,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的宙刘。 我是一名探鬼主播苍姜,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼悬包!你這毒婦竟也來了衙猪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎垫释,沒想到半個月后丝格,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饶号,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年铁追,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茫船。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡琅束,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出算谈,到底是詐尸還是另有隱情涩禀,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布然眼,位于F島的核電站艾船,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏高每。R本人自食惡果不足惜屿岂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鲸匿。 院中可真熱鬧爷怀,春花似錦、人聲如沸带欢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乔煞。三九已至吁朦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間渡贾,已是汗流浹背逗宜。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留空骚,地道東北人纺讲。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像府怯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子防楷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

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

  • 原教程內(nèi)容詳見精益 React 學(xué)習(xí)指南牺丙,這只是我在學(xué)習(xí)過程中的一些閱讀筆記,個人覺得該教程講解深入淺出,比目前大...
    leonaxiong閱讀 2,833評論 1 18
  • JSX 知識準(zhǔn)備 JSX 并不是一門全新的語言冲簿,僅僅是一個語法糖粟判,允許開發(fā)者在javascript中編寫XML語言...
    艾倫先生閱讀 4,504評論 4 20
  • 目前,react組件有三種寫法峦剔,分別是es5的createClass寫法档礁,es6的class寫法,以及statel...
    ZoomFunc閱讀 1,647評論 0 1
  • 文■子曰無風(fēng) 最近羹幸,《對不起,我的朋友都很貴》辫愉、《對不起栅受,我的醫(yī)生朋友都貴》刷爆了朋友圈,也該出一個攝影師版的了恭朗。...
    子曰無風(fēng)閱讀 230評論 0 0
  • 作者:枚河 (一)路永生 我覺得自己的腦子突然恍惚了屏镊,仿佛我這幾天都在不停地重復(fù)。 走過安遠(yuǎn)門痰腮,門洞里的老頭坐在破...
    枚河閱讀 501評論 0 2