我們知道React Native之所以能在移動(dòng)設(shè)備上運(yùn)行起來恬总,是因?yàn)镽eact Native和原生設(shè)備之間有一種交互前普,以iOS為例,React Native 能夠運(yùn)行起來壹堰,全靠 objective-c 和 JavaScript 的交互拭卿。對于頁面的渲染來說,React的渲染都是以組件為單位贱纠,那么這個(gè)React組件到底是怎么用原生組件渲染的呢峻厚?
<h2>React組件的產(chǎn)生過程與生命周期</h2>
<h4>ReactElement</h4>
用于描述虛擬節(jié)點(diǎn),它們可以通過 React.createElement 方法或 jsx 寫法被創(chuàng)建。
ReactElement分為 DOM Element 和 Component Elements 兩類谆焊,前者是dom組件后者是自定義組件如
class MyText extends React.Component {
render() {
...
}
}
<h4>初始化過程</h4>
上一張圖
1.通過render()方法惠桃,將element的虛擬根節(jié)點(diǎn)渲染到container中
2.接下來根據(jù)element的類型分成三種情況,String還是ReactElement中的DOM Element或Component Elements 辖试,依次實(shí)例化ReactDOMTextComponent , ReactDOMComponent , ReactCompositeComponent 類
3.ReactDOMTextComponent , ReactDOMComponent , ReactCompositeComponent 用于管理 ReactElement ,負(fù)責(zé)將不同的 ReactElement 轉(zhuǎn)化成DOM辜王,并更新DOM
<h4>生命周期</h4>
當(dāng)組件按上文方式初始化后,就有了生命周期
生命周期中的每個(gè)階段都有相應(yīng)的回調(diào)函數(shù)罐孝,用于控制和操作組件呐馆。
<h5>初始化階段</h5>
圖中最上面的框
<b>getDefaultProps</b>和<b> getInitialState </b>
用于初始化組件的屬性和狀態(tài)
<b>componentWillMount</b>
在第一次繪制 render() 之前觸發(fā),在整個(gè)生命周期中只被觸發(fā)一次莲兢。
<b>componentDidMount</b>
在第一次繪制 render()之后觸發(fā)汹来,在整個(gè)生命周期中只被觸發(fā)一次。這個(gè)函數(shù)之后改艇,就進(jìn)入了穩(wěn)定運(yùn)行狀態(tài)收班,等待事件觸發(fā)。
<h5>運(yùn)行階段</h5>
<b>componentWillReceiveProps</b>
組件收到新的屬性(props)時(shí)觸發(fā)谒兄,輸入?yún)?shù) nextProps 是即將被設(shè)置的屬性摔桦,舊的屬性還是可以通過 this.props 來獲取。常在此處通過調(diào)用 this.setState() 來更新的組件狀態(tài)舵变。
<b> shouldComponentUpdate </b>
組件接收到新的屬性和狀態(tài)改變的話酣溃,都會(huì)觸發(fā),輸入?yún)?shù) nextProps 和上面的 componentWillReceiveProps 函數(shù)一樣纪隙, nextState 表示組件即將更新的狀態(tài)值赊豌。這個(gè)函數(shù)的返回值決定是否需要更新組件,如果 true 表示需要更新绵咱,繼續(xù)走后面的更新流程碘饼。否者,則不更新。
<b> componentWillUpdate </b>
更新渲染前調(diào)用,輸入?yún)?shù)與 shouldComponentUpdate 一樣,但不要在此更新狀態(tài)
<b> componentDidUpdate </b>
更新渲染后調(diào)用艾恼,
<h5>卸載階段</h5>
<b> componentWillUnmount </b>
組件要被從界面上移除的時(shí)候住涉,就會(huì)觸發(fā)。一般在次進(jìn)行一些清理計(jì)時(shí)器之類的結(jié)尾工作
<h2>怎樣用原生組件渲染的</h2>
既然React Native能在移動(dòng)設(shè)備上運(yùn)行钠绍,那么上述的react組件是怎么用原生組件渲染的呢舆声?
<h4>react-native應(yīng)用的啟動(dòng)過程</h4>
<b>1.Native的初始化</b>
以ios為例,包括
讀取 JavaScript 源碼
初始化模塊信息
初始化 JavaScript 代碼的執(zhí)行器柳爽,即 RCTJSCExecutor 對象
生成模塊列表并寫入 JavaScript 端
執(zhí)行 JavaScript 源碼
這五個(gè)階段媳握,這里不是本文的描述點(diǎn),所以略過磷脯。這個(gè)地方和react-native的通訊機(jī)制打算在之后深入探討學(xué)習(xí)蛾找。
<b>2.Native端執(zhí)行初始化React上下文</b>
調(diào)用JS端AppRegistry.runApplication(key,params),key為模塊/組件名稱.
<b>3.JS端找到注冊的對應(yīng)啟動(dòng)組件赵誓,執(zhí)行renderApplication渲染整個(gè)應(yīng)用</b>
renderApplication會(huì)執(zhí)行如下代碼
ReactNative.render(
<AppContainer>
<RootComponent
{...initialProps}
rootTag={rootTag}
/>
</AppContainer>,
rootTag
);
其中AppContainer是一個(gè)JS組件打毛,使用View包裹了根組件,開發(fā)時(shí)工具Inspector俩功、YellowBox都是在這個(gè)組件中加載幻枉,RootComponent是傳入的根組件。
<b>4.找到j(luò)s端注冊的組件</b>
js通過AppRegistry注冊組件
AppRegistry.registerComponent('MyApp', rootComponent);
<b>5.Native端渲染組件</b>
以ios為例
self.rctRootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"MyApp"
initialProperties:nil
launchOptions:nil];
位于 AppDelegate 文件中绑雄,用戶能看到的一切內(nèi)容都來源于這個(gè) RootView 展辞,所有的初始化工作也都在這個(gè)方法內(nèi)完成。
<h4>原生組件渲染</h4>
應(yīng)用啟動(dòng)的最后階段就是JS端開始渲染根組件万牺,那么其它react組件怎么用原生組件渲染的呢?我們先看render()方法做了什么
render() {
return (
<Image source={Styles.picUrl}/>
)
}
將jsx翻譯一下就是
render() {
return (
React.createElement(Image, { source: Styles.picUrl })
)
}
回想一下上文中ReactElement的描述
ReactElement.createElement = function (type, config, children){ ... }
在react-native下ReactNative的UI組件通過requireNativeComponent -> createReactNativeComponentClass -> ReactNativeBaseComponent下mountComponent的調(diào)用關(guān)系洽腺,最終在mountComponent中調(diào)用UIManager組件創(chuàng)建View
UIManager.createView(tag, this.viewConfig.uiViewClassName, nativeTopRootTag, updatePayload);
UIManager是一個(gè)NativeModule脚粟,JS端可訪問≌号螅可通過createView核无,
updateView方法來創(chuàng)建和更新View。
之后原生組件的實(shí)現(xiàn)方法藕坯,首先是Image組件JS端代碼团南,需要requireNativeComponent加載原生組件以ios為例
const RCTImageView = requireNativeComponent('RCTImageView', Image);
返回
<RCTImageView
{...this.props}
style={style}
resizeMode={resizeMode}
tintColor={tintColor}
source={sources}
/>
這就創(chuàng)建出原生組件了,之后的事情就是js端的邏輯對原生組件進(jìn)行控制炼彪,這就是react-native的通訊機(jī)制的問題了吐根。