2019-01-08

Welcome to React!

React是什么矿咕?為什么要使用它抢肛?

React是Facebook內(nèi)部的一個(gè)JavaScript類庫,已于2013年開源碳柱,可用于創(chuàng)建Web用戶交互界面捡絮。它引入了一種新的方式來處理瀏覽器DOM。那些需要手動(dòng)更新的DOM莲镣、費(fèi)力地記錄每一個(gè)狀態(tài)的日子一去不復(fù)返了————這種老舊的方式既不具備擴(kuò)展性福稳,又很難加入新的功能,就算可以瑞侮,也是冒著很大的風(fēng)險(xiǎn)灵寺。React使用很新穎的方式解決了這些問題。你只需聲明式地定義各個(gè)時(shí)間點(diǎn)的用戶界面区岗,而無需關(guān)心在數(shù)據(jù)變化時(shí)需要更新哪一部分DOM略板。在任何時(shí)間點(diǎn),React都能夠以最小的DOM修改來更新整個(gè)應(yīng)用程序慈缔。

一叮称、HTML模板

使用React的網(wǎng)頁源碼,結(jié)構(gòu)大致如下:

<!DOCTYPE html>React//**Our code goes here!**

上面代碼有兩個(gè)地方需要注意藐鹤。首先瓤檐,最后一個(gè)<script>標(biāo)簽的type屬性為text/babel。這是因?yàn)?React 獨(dú)有的 JSX 語法娱节,跟 JavaScript 不兼容挠蛉。凡是使用 JSX 的地方,都要加上type="text/babel"肄满。

其次谴古,上面代碼一共用了三個(gè)庫:react.js、react-dom.js和Browser.js稠歉,它們必須首先加載掰担。其中,react.js是 React 的核心庫怒炸,react-dom.js是提供與 DOM 相關(guān)的功能带饱,Browser.js的作用是將 JSX 語法轉(zhuǎn)為 JavaScript 語法,這一步很消耗時(shí)間阅羹,實(shí)際上線的時(shí)候勺疼,應(yīng)該將它放到服務(wù)器完成教寂。

二、ReaceDOM.render()

React.render(

Hello, World!

,document.getElementById('example'));

上面代碼將一個(gè)h1標(biāo)題执庐,插入example節(jié)點(diǎn)

三孝宗、JSX語法

上面的代碼,HTML語言直接在JavaScript語言之中耕肩,不加任何引號(hào),這就是JSX的語法问潭,它允許HTML與JavaScript的渾寫

varnames = ['xiaoxin','xiaoqiang','xiaowanzi'];React.render(

{? ? ? names.map(function (name) {? ? ? ? return
Hello, {name}!
})? ? }
,document.getElementById('example'));

上面代碼體現(xiàn)了 JSX 的基本語法規(guī)則:遇到 HTML 標(biāo)簽(以<開頭)猿诸,就用 HTML 規(guī)則解析;遇到代碼塊(以{開頭)狡忙,就用 JavaScript 規(guī)則解析梳虽。

JSX允許直接在模板插入JavaScript變量。如果這個(gè)變量是一個(gè)數(shù)組灾茁,則會(huì)展開這個(gè)數(shù)組的所有成員

vararr = [

Hello world!

,?

React is awesome!

,];ReactDOM.render(
{arr}
,document.getElementById('example'));

四窜觉、組件

varHelloMessage = React.createClass({render:function(){return

Hello {this.props.name}

;? }});ReactDOM.render(,? document.getElementById('example'));

上面代碼中,變量HelloMessage就是一個(gè)組件類北专。模板插入<HelloMessage />時(shí)禀挫,會(huì)自動(dòng)生成HelloMessage的一個(gè)實(shí)例(下文的"組件"都指組件類的實(shí)例)。所有組件類都必須有自己的render方法拓颓,用于輸出組件语婴。

注意,組件類的第一個(gè)字母必須大寫驶睦,否則會(huì)報(bào)錯(cuò)砰左,比如HelloMessage不能寫成helloMessage。另外场航,組件類只能包含一個(gè)頂層標(biāo)簽缠导,否則也會(huì)報(bào)錯(cuò)。

varHelloMessage = React.createClass({? render:function(){return(? ? ? ?

? ? ? ? ? ? Hello {this.props.name}? ? ? ?

? ? ? ?

? ? ? ? ? ? some text? ? ? ?

? ? )? }});

上面代碼會(huì)報(bào)錯(cuò)溉痢,因?yàn)镠elloMessage組件包含了兩個(gè)頂層標(biāo)簽:h1和p僻造。

組件的用法與原生的 HTML 標(biāo)簽完全一致,可以任意加入屬性孩饼,比如<HelloMessage name="John">嫡意,就是HelloMessage組件加入一個(gè)name屬性,值為John捣辆。組件的屬性可以在組件類的this.props對(duì)象上獲取蔬螟,比如name屬性就可以通過this.props.name讀取。

五汽畴、this.props.children

this.props對(duì)象的屬性與組件的屬性一一對(duì)應(yīng)旧巾,但是有一個(gè)例外耸序,就是this.props.children屬性。

varNotesList = React.createClass({render:function(){return(

    {? ? ? ? ? React.Children.map(this.props.children, function (child) {? ? ? ? ? ? return
  1. {child}
  2. ;? ? ? ? ? })? ? ? ? }
);? }});ReactDOM.render(xiaoxinxiaoqiangxiaowanzi,document.getElementById('example'));

上面代碼的 NoteList 組件有兩個(gè)span子節(jié)點(diǎn)鲁猩,它們都可以通過this.props.children讀取坎怪。

這里需要注意,this.props.children的值有三種可能:如果當(dāng)前組件沒有子節(jié)點(diǎn)廓握,它就是undefined; 如果有一個(gè)子節(jié)點(diǎn)搅窿,數(shù)據(jù)類型是object;如果有多個(gè)子節(jié)點(diǎn)隙券,數(shù)據(jù)類型就是array男应。所以,處理this.props.children的時(shí)候要小心娱仔。

React 提供一個(gè)工具方法React.Children來處理this.props.children沐飘。我們可以用React.Children.map來遍歷子節(jié)點(diǎn),而不用擔(dān)心this.props.children的數(shù)據(jù)類型是undefined還是object牲迫。

六耐朴、PropTypes

組件的屬性可以接受任意值,字符串盹憎、對(duì)象筛峭、函數(shù)等等都可以。有時(shí)陪每,我們需要一種機(jī)制蜒滩,驗(yàn)證別人使用組件時(shí),提供的參數(shù)是否符合要求奶稠。

組件類的PropTypes屬性俯艰,就是用來驗(yàn)證組件實(shí)例的屬性是否符合要求。

varMyTitle = React.createClass({propTypes: {title: React.PropTypes.string.isRequired,? },render:function(){return

{this.props.title}

;? }});

上面的Mytitle組件有一個(gè)title屬性锌订。PropTypes告訴 React竹握,這個(gè)title屬性是必須的,而且它的值必須是字符串×酒現(xiàn)在啦辐,我們?cè)O(shè)置title屬性的值是一個(gè)數(shù)值。

vardata =123;ReactDOM.render(,? document.getElementById('example'));

這樣一來蜈项,title屬性就通不過驗(yàn)證了芹关。控制臺(tái)會(huì)顯示一行警告信息,但是能正常顯示紧卒,這個(gè)地方不是很明白侥衬?

七、getDefaultProps

可以為組件添加此函數(shù)來設(shè)置屬性的默認(rèn)值。不過轴总,這應(yīng)該只針對(duì)那些非必須屬性直颅。

varMyTitle = React.createClass({getDefaultProps:function(){return{title:'Hello World'};? },render:function(){return

{this.props.title}

;? }});ReactDOM.render(,? document.getElementById('example'));

八、獲取真實(shí)的DOM節(jié)點(diǎn)

組件并不是真實(shí)的 DOM 節(jié)點(diǎn)怀樟,而是存在于內(nèi)存之中的一種數(shù)據(jù)結(jié)構(gòu)功偿,叫做虛擬 DOM (Virtual DOM)。只有當(dāng)它插入文檔以后往堡,才會(huì)變成真實(shí)的 DOM 械荷。根據(jù) React 的設(shè)計(jì),所有的 DOM 變動(dòng)虑灰,都先在虛擬 DOM 上發(fā)生吨瞎,然后再將實(shí)際發(fā)生變動(dòng)的部分,反映在真實(shí) DOM上瘩缆,這種算法叫做 DOM diff ,它可以極大提高網(wǎng)頁的性能表現(xiàn)佃蚜。

但是庸娱,有時(shí)需要從組件獲取真實(shí) DOM 的節(jié)點(diǎn)像屋,這時(shí)就要用到ref屬性

varMyComponent = React.createClass({? handleClick:function(){? ? this.refs.myTextInput.focus();? },? render:function(){return(? ? ?

? ? ? ? ? ? ? ? ? ? ?
? ? );? }});ReactDOM.render(? ,? document.getElementById('example'));

上面代碼中通危,組件MyComponent的子節(jié)點(diǎn)有一個(gè)文本輸入框,用于獲取用戶的輸入熙卡。這時(shí)就必須獲取真實(shí)的 DOM 節(jié)點(diǎn)洲脂,虛擬 DOM 是拿不到用戶輸入的斤儿。為了做到這一點(diǎn),文本輸入框必須有一個(gè)ref屬性恐锦,然后this.refs.[refName]就會(huì)返回這個(gè)真實(shí)的 DOM 節(jié)點(diǎn)往果。

需要注意的是,由于this.refs.[refName]屬性獲取的是真實(shí) DOM 一铅,所以必須等到虛擬 DOM 插入文檔以后陕贮,才能使用這個(gè)屬性,否則會(huì)報(bào)錯(cuò)潘飘。上面代碼中肮之,通過為組件指定Click事件的回調(diào)函數(shù),確保了只有等到真實(shí) DOM 發(fā)生Click事件之后卜录,才會(huì)讀取this.refs.[refName]屬性戈擒。

九、this.state

組件免不了要與用戶互動(dòng)艰毒,React 的一大創(chuàng)新筐高,就是將組件看成是一個(gè)狀態(tài)機(jī),一開始有一個(gè)初始狀態(tài),然后用戶互動(dòng)凯傲,導(dǎo)致狀態(tài)變化犬辰,從而觸發(fā)重新渲染 UI。

varLikeButton = React.createClass({getInitialState:function(){return{liked:false};? },handleClick:function(event){this.setState({liked: !this.state.liked});? },render:function(){vartext =this.state.liked ?'like':'haven\'t liked';return(You {text} this. Click to toggle.);? }});ReactDOM.render(,? document.getElementById('example'));

上面代碼是一個(gè)LikeButton組件冰单,它的getInitialState方法用于定義初始狀態(tài)幌缝,也就是一個(gè)對(duì)象,這個(gè)對(duì)象可以通過this.state屬性讀取诫欠。當(dāng)用戶點(diǎn)擊組件涵卵,導(dǎo)致狀態(tài)變化,this.setState方法就修改狀態(tài)值荒叼,每次修改以后轿偎,自動(dòng)調(diào)用this.render方法,再次渲染組件被廓。

由于this.props和this.state都用于描述組件的特性坏晦,可能會(huì)產(chǎn)生混淆。一個(gè)簡單的區(qū)分方法是嫁乘,this.props表示那些一旦定義昆婿,就不再改變的特性,而this.state是會(huì)隨著用戶互動(dòng)而產(chǎn)生變化的特性蜓斧。

十仓蛆、表單

用戶在表單填入的內(nèi)容,屬于用戶跟組件的互動(dòng)挎春,所以不能用this.props讀取看疙。

varInput = React.createClass({getInitialState:function(){return{value:'Hello!'};? },handleChange:function(event){this.setState({value: event.target.value});? },render:function(){varvalue =this.state.value;return(

{value}

);? }});ReactDOM.render(,? document.getElementById('example'));

上面代碼中,文本輸入框的值直奋,不能用this.props.value讀取能庆,而要定義一個(gè)onChange事件的回調(diào)函數(shù),通過event.target.value讀取用戶輸入的值脚线。同時(shí)也可以利用ref獲取相味。

十一、組件的生命周期

組件的生命周期

React為每個(gè)組件提供了生命周期鉤子函數(shù)去響應(yīng)不同的時(shí)刻——創(chuàng)建時(shí)殉挽、存在期銷毀時(shí)丰涉。

創(chuàng)建時(shí)

getDefaultProps

getInitialState

componentWillMount

render

componentDidMount

getDefaultProps

對(duì)于組件類來說,只會(huì)被調(diào)用一次斯碌。對(duì)于那些么有被父輩組件指定props屬性的新建實(shí)例來說一死,這個(gè)方法返回的對(duì)象可用于實(shí)例設(shè)置默認(rèn)的props值。

getInitialState

對(duì)于組件的每個(gè)實(shí)例來講傻唾,這個(gè)方法的調(diào)用次數(shù)有且只有一次投慈。在這里你將有機(jī)會(huì)初始化每個(gè)實(shí)例的state承耿。與getDefaultProps方法不同的是,每個(gè)實(shí)例創(chuàng)建時(shí)該方法都會(huì)調(diào)用一次伪煤。在這個(gè)方法里加袋,你已經(jīng)可以訪問到this.props。

componentWillMount

該方法在完成首次渲染之前被調(diào)用抱既。這也是在render方法調(diào)用前可以修改組件state的最后一次機(jī)會(huì)职烧。

render

在這里你會(huì)創(chuàng)建一個(gè)虛擬DOM,用來表示組件的輸出防泵。對(duì)于一個(gè)組件來說蚀之,render是唯一一個(gè)必須的方法,并且有特點(diǎn)的規(guī)則捷泞。rander方法需要滿足下面幾點(diǎn):

只能通過this.props和this.state訪問數(shù)據(jù)足删。

可以返回null、false或者任何React組件锁右。

只能出現(xiàn)一個(gè)頂級(jí)組件失受。

必須純凈,意味著不能改變組件的狀態(tài)或者修改DOM的輸出咏瑟。

render方法返回的結(jié)果不是真正的DOM拂到,而是一個(gè)虛擬的表現(xiàn),React隨后會(huì)把它和真實(shí)的DOM作對(duì)比响蕴,來判斷是否有必要做出修改谆焊。

componentDidMount

在render方法成功調(diào)用并且真實(shí)的DOM已經(jīng)被渲染之后惠桃,你可以通過this.getDOMNode方法訪問它浦夷。

當(dāng)react運(yùn)行在服務(wù)端時(shí),componentDidMount方法不會(huì)被調(diào)用辜王。

存在期

此時(shí)劈狐,組件已經(jīng)渲染好并且用戶可以與它進(jìn)行交互。通常是通過依次鼠標(biāo)點(diǎn)擊呐馆、手指點(diǎn)按或者鍵盤事件來觸發(fā)一個(gè)事件處理器肥缔。隨著用戶改變了組件或者整個(gè)應(yīng)用的state,便會(huì)有新的state流入組件樹汹来,并且我們將會(huì)獲得操縱它的機(jī)會(huì)续膳。

componentWillReceiveProps

shouldComponentUpdate

componentWillUpdate

render

componentDidUpdate

componentWillReceiveProps

在任意時(shí)刻,組件的props都可以通過父輩組件來改變收班。出現(xiàn)這種情況時(shí)坟岔,此方法被調(diào)用,你也將獲得更改props對(duì)象以及更新state的機(jī)會(huì)摔桦。

shouldComponentUpdate

React非成绺叮快承疲。不過你還可以讓它更快——通過此方法在組件渲染時(shí)進(jìn)行精確優(yōu)化。

如果你確定某個(gè)組件或者它的子組件不需要渲染新的props或者state鸥咖,則該方法會(huì)返回false

在首次渲染期間或者調(diào)用了forceUpdate方法后燕鸽,這個(gè)方法不會(huì)被調(diào)用

返回false則是在告訴React要跳過調(diào)用render方法,以及位于render前后的鉤子函數(shù)componentWillUpdate和componentDidUpdate啼辣。

componentWillUpdate

和componentWillMount方法類似啊研,組件會(huì)在接收到新的props或者state進(jìn)行渲染之前調(diào)用該方法。注意熙兔,你不可以在該方法中更新state或者props悲伶,而應(yīng)該借助componentWillReceiveProps方法在運(yùn)行中更新state。

componentDidUpdate

和componentDidMount方法類似住涉,該方法給了我們更新已經(jīng)渲染好的DOM的機(jī)會(huì)麸锉。

銷毀時(shí)

每當(dāng)React使用完一個(gè)組件,這個(gè)組件就必須從DOM中卸載隨后被銷毀舆声。此時(shí)花沉,僅有的一個(gè)鉤子函數(shù)會(huì)做出響應(yīng),完成所有的清理和銷毀工作媳握,這很必要碱屁。

componentWillUnmount

最后,隨著一個(gè)組件從它的結(jié)構(gòu)中移除蛾找,這個(gè)組件的生命也走到了盡頭娩脾。該方法會(huì)在組件被移除之前調(diào)用,讓你有機(jī)會(huì)做一些清理工作打毛。你在componentDidMount方法中添加的所有任務(wù)都需要在該方法中撤銷柿赊,比如創(chuàng)建的定時(shí)器或者添加的事件監(jiān)聽器。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(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
  • 文/蒼蘭香墨 我猛地睜開眼硬纤,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了碘梢?” 一聲冷哼從身側(cè)響起咬摇,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤伐蒂,失蹤者是張志新(化名)和其女友劉穎煞躬,沒想到半個(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
  • 正文 我出身青樓,卻偏偏與公主長得像脆栋,于是被迫代替她去往敵國和親倦卖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

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

  • 作為一個(gè)合格的開發(fā)者椿争,不要只滿足于編寫了可以運(yùn)行的代碼怕膛。而要了解代碼背后的工作原理;不要只滿足于自己的程序...
    六個(gè)周閱讀 8,448評(píng)論 1 33
  • 使用 create-react-app 快速構(gòu)建 React 開發(fā)環(huán)境 項(xiàng)目的目錄結(jié)構(gòu)如下: React JSX ...
    majun00閱讀 510評(píng)論 0 0
  • 1 安裝 React 的安裝包秦踪,可以到官網(wǎng)下載褐捻。不過,React Demos已經(jīng)自帶 React源碼椅邓,不用另外安裝...
    Kevin_Junbaozi閱讀 990評(píng)論 0 1
  • 現(xiàn)在最熱門的前端框架柠逞,毫無疑問是 React 。上周景馁,基于 React 的 React Native 發(fā)布板壮,結(jié)果一...
    sakura_L閱讀 431評(píng)論 0 0
  • 命運(yùn)似乎總喜歡和我們開玩笑,誰會(huì)想到自己會(huì)因?yàn)楫?dāng)初的一句玩笑話而變成現(xiàn)在的一名警校...
    Sumprmi閱讀 1,303評(píng)論 0 1