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(
上面代碼體現(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(四窜觉、組件
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
- {child} ;? ? ? ? ? })? ? ? ? }
上面代碼的 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(? ? ?
上面代碼中通危,組件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}
上面代碼中,文本輸入框的值直奋,不能用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)聽器。