(申明: 此系列教程,轉(zhuǎn)載旋之華微信公眾號(hào),如有侵權(quán) . 通知?jiǎng)h除~)
(大家可以添加他的微信公眾號(hào)了解更多內(nèi)容.)
對(duì)于習(xí)慣了iOS開發(fā)的同學(xué),可能會(huì)對(duì)React Native中組件的生命周期很困惑缰猴。在iOS中有一個(gè)ViewDidLoad來(lái)初始化憎蛤,那么在RN中害驹,又是在哪里呢杖刷?
一苹粟、看圖分析
在下圖中描述了React Native中組件的生命周期在刺,我們可以根據(jù)其中的執(zhí)行順序在對(duì)應(yīng)的函數(shù)中做對(duì)應(yīng)的操作调塌。
React Native組件的生命周期大致上可以劃分為
實(shí)例化階段
牍氛、
存在階段
和
銷毀階段
,其中最常用的為
實(shí)例化階段
烟阐,該階段就是組件的構(gòu)建搬俊、展示時(shí)期,需要我們根據(jù)幾個(gè)函數(shù)的調(diào)用過程蜒茄,控制好組件的展示和邏輯的處理唉擂。
二、實(shí)例化階段函數(shù)功能分析
getDefaultProps
該函數(shù)用于初始化一些默認(rèn)的屬性檀葛,通常會(huì)將固定的內(nèi)容放在這個(gè)函數(shù) 中進(jìn)行初始化和賦值玩祟;
在組件中,可以利用
this.props
獲取在這里初始化它的屬性屿聋,由于組件初始化后空扎,再次使用該組件不會(huì)調(diào)用getDefaultProps函數(shù),所以組件自己不可以自己修改props(即:props可認(rèn)為是只讀的)润讥,只可由其他組件調(diào)用它時(shí)在外部修改转锈。
getInitialState
該函數(shù)是用于對(duì)組件的一些狀態(tài)進(jìn)行初始化;
由于該函數(shù)不同于getDefaultProps楚殿,在以后的過程中撮慨,會(huì)再次調(diào)用,所以可以將控制控件的狀態(tài)的一些變量放在這里初始化脆粥,如控件上顯示的文字砌溺,可以通過
this.state
來(lái)獲取值,通過
this.setState
來(lái)修改state值变隔, 比如:
<pre style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important;">
this.setState({
activePage: activePage,
currentX: contentOffSetX
});
</pre>
注意:
一旦調(diào)用了this.setState方法规伐,組件一定會(huì)調(diào)用render方法,對(duì)組件進(jìn)行再次的渲染匣缘,不過猖闪,如果React框架會(huì)自動(dòng)根據(jù)DOM的狀態(tài)來(lái)判斷是否需要真正的渲染。
componentWillMount
相當(dāng)于OC中的ViewWillAppear方法孵户,在
組件將要被加載在視圖上之前調(diào)用萧朝,功能相對(duì)較少。
render
render是一個(gè)組件中必須有的方法夏哭,本質(zhì)上是一個(gè)函數(shù)检柬,并返回JSX或其他組件來(lái)構(gòu)成DOM,和Android的XML布局類似,注意:
只能返回一個(gè)頂級(jí)元素
;
此外何址,在render函數(shù)中里逆,只可通過
this.state
和
this.props
來(lái)訪問在之前函數(shù)中初始化的數(shù)據(jù)值 。
componentDidMount
在調(diào)用了render方法后用爪,組件加載成功并被成功渲染出來(lái)以后原押,所要執(zhí)行的后續(xù)操作,一般會(huì)在這個(gè)函數(shù)中處理網(wǎng)絡(luò)請(qǐng)求等加載數(shù)據(jù)的操作偎血;
因?yàn)閁I已經(jīng)成功被渲染出來(lái)诸衔, 所以放在這個(gè)函數(shù)里進(jìn)行請(qǐng)求操作,不會(huì)出現(xiàn)UI上的錯(cuò)誤颇玷。
下圖是利用了fetch API來(lái)異步請(qǐng)求Web API來(lái)加載數(shù)據(jù):
三笨农、存在期階段函數(shù)功能分析
componentWillReceiveProps
指父元素對(duì)組件的props或state進(jìn)行了修改
shouldComponentUpdate
一般用于優(yōu)化,可以返回false或true來(lái)控制是否進(jìn)行渲染
componentWillUpdate
組件刷新前調(diào)用帖渠,類似componentWillMount
componentDidUpdate
更新后的hook
四谒亦、銷毀期階段函數(shù)功能分析
用于清理一些無(wú)用的內(nèi)容,如:點(diǎn)擊事件Listener空郊,只有一個(gè)過程:
componentWillUnmount
****五份招、常用知識(shí)點(diǎn)分析****
****5.1 this.state ****
開發(fā)中組件免不了要與用戶互動(dòng),React 的一大創(chuàng)新狞甚,就是將組件看成是一個(gè)狀態(tài)機(jī)锁摔,一開始有一個(gè)初始狀態(tài),然后用戶互動(dòng)入愧,導(dǎo)致狀態(tài)變化鄙漏,從而觸發(fā)重新渲染 UI。
舉個(gè)例子:
當(dāng)用戶點(diǎn)擊組件棺蛛,導(dǎo)致狀態(tài)變化, **this.setState** 方法就修改狀態(tài)值巩步,每次修改以后旁赊,自動(dòng)調(diào)用 **this.render** 方法,再次渲染組件椅野。
可以把組件看成一個(gè)“狀態(tài)機(jī)”. 根據(jù)不同的status有不同的UI展示终畅。只要使用setState改變狀態(tài)值,根據(jù)diff算法算出來(lái)有差以后竟闪,就會(huì)執(zhí)行ReactDom的render方法离福,重新渲染頁(yè)面。
注意:由于 this.props 和 this.state 都用于描述組件的特性炼蛤,可能會(huì)產(chǎn)生混淆妖爷。一個(gè)簡(jiǎn)單的區(qū)分方法是,this.props 表示那些一旦定義理朋,就不再改變的特性絮识,而 this.state 是會(huì)隨著用戶互動(dòng)而產(chǎn)生變化的特性绿聘。
5.2 獲取真實(shí)的DOM節(jié)點(diǎn)
在React Native中,組件并不是真實(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)頁(yè)的性能表現(xiàn)。
但是务热,有時(shí)需要從組件獲取真實(shí) DOM 的節(jié)點(diǎn)忆嗜,這時(shí)就要用到
ref
屬性;
下圖通過一個(gè)案例來(lái)演示:
運(yùn)行結(jié)果如下:
上面代碼中,組件 View 的子節(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]
屬性羽嫡。
六本姥、案例實(shí)操
案例主要技術(shù)點(diǎn):
充分利用了RN生命周期的鉤子函數(shù),實(shí)現(xiàn)界面刷新杭棵。
1.1 利用控件的索引index計(jì)算出控件所在的行號(hào)和列號(hào)
1.2 利用列號(hào)計(jì)算控件的x值
1.3 利用行號(hào)計(jì)算控件的y值
案例思路截圖:
案例核心代碼:
****案例運(yùn)行效果截圖:****
八婚惫、總結(jié)
React Native組件的生命周期,經(jīng)歷了Mount->Update->Unmount這三個(gè)大的過程,即從創(chuàng)建到銷毀的過程辰妙,結(jié)合OC中的開發(fā)經(jīng)驗(yàn)鹰祸,我們?cè)谝陨系幕A(chǔ)上應(yīng)該可以快速的上手React Native的開發(fā)。
九密浑、引用
9.1 什么是DOM Diff算法
Web界面由DOM樹來(lái)構(gòu)成蛙婴,當(dāng)其中某一部分發(fā)生變化時(shí),其實(shí)就是對(duì)應(yīng)的某個(gè)DOM節(jié)點(diǎn)發(fā)生了變化尔破。在React中街图,構(gòu)建UI界面的思路是由當(dāng)前狀態(tài)決定界面。前后兩個(gè)狀態(tài)就對(duì)應(yīng)兩套界面懒构,然后由React來(lái)比較兩個(gè)界面的區(qū)別餐济,這就需要對(duì)DOM樹進(jìn)行Diff算法分析。
即給定任意兩棵樹胆剧,找到最少的轉(zhuǎn)換步驟絮姆。但是標(biāo)準(zhǔn)的的Diff算法復(fù)雜度需要O(n^3),這顯然無(wú)法滿足性能要求秩霍。要達(dá)到每次界面都可以整體刷新界面的目的篙悯,勢(shì)必需要對(duì)算法進(jìn)行優(yōu)化。這看上去非常有難度铃绒,然而Facebook工程師卻做到了鸽照,他們結(jié)合Web界面的特點(diǎn)做出了兩個(gè)簡(jiǎn)單的假設(shè),使得Diff算法復(fù)雜度直接降低到O(n)
兩個(gè)相同組件產(chǎn)生類似的DOM結(jié)構(gòu)颠悬,不同的組件產(chǎn)生不同的DOM結(jié)構(gòu)矮燎;
-
對(duì)于同一層次的一組子節(jié)點(diǎn),它們可以通過唯一的id進(jìn)行區(qū)分赔癌。
算法上的優(yōu)化是React整個(gè)界面Render的基礎(chǔ)诞外,事實(shí)也證明這兩個(gè)假設(shè)是合理而精確的,保證了整體界面構(gòu)建的性能届榄。
9.2 ES5和ES6的差異化浅乔?
es5,es6 都是對(duì) ecmascript規(guī)范的補(bǔ)充铝条,es5已經(jīng)大規(guī)模使用了,es6目前可能在個(gè)別平臺(tái)存在瀏覽器兼容性問題席噩; 其中箭頭函數(shù)()=>()是ES6獨(dú)有的班缰。
區(qū)別1:創(chuàng)建組件
組件是一個(gè)自定義的js對(duì)象,在es5中使用React.createClass()悼枢;在es6中必須繼承React.component埠忘,然后進(jìn)行創(chuàng)建。
ES5的寫法:
ES6的寫法:
區(qū)別2:組件的屬性props
在ES6中,其為屬性:defaultProps(可以標(biāo)識(shí)static定義在class內(nèi)莹妒,也可以定義在class外)名船,而
在ES5中,其為方法:getDefaultProps: function(){return {name:value}};
ES5:
ES6:
區(qū)別3:
組件的狀態(tài)state
ES5:
ES6: