RN使用經(jīng)驗(yàn)

rn版本:0.55
原生和rn混編

TouchableWithoutFeedback系列組件內(nèi)部包含的Text設(shè)置lineHeight時(shí),在某些安卓手機(jī)上可能導(dǎo)致文本顯示出現(xiàn)被切割現(xiàn)象

安卓的部分組件如Text無法撐開父視圖的寬高
安卓和ios的Text組件文本內(nèi)置間隙差異很大
Dimensions.get('window’)獲取的屏幕寬高,在某些安卓機(jī)型上面有問題,例如沒有考慮頂部狀態(tài)欄和底部按鍵欄目,需要原生另外寫方法判斷

對Animated.View等動(dòng)畫組件,設(shè)置transform的scale為0在某些安卓手機(jī)上無法完全隱藏,可以配合設(shè)置opacity為0實(shí)現(xiàn)效果

rn執(zhí)行的代碼中涉及到原生代碼有改動(dòng),則該rn包不能下發(fā)給舊的app版本,需要做版本控制

rn頁面實(shí)現(xiàn)類似viewwillappera的代理方法
前提是所有的rn頁面的跳轉(zhuǎn)是由原生控制,rn僅僅是顯示作用。跳轉(zhuǎn)到rn頁面代碼如下

RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:properties];
RNViewController *vc = [[HCZRNViewController alloc] init];
[vc.view addSubview:rootView];
[nav pushViewController:vc animated:YES];

RNViewController就是一個(gè)普通的UIViewController,在內(nèi)部的viewWillAppear中發(fā)出通知,通過RCTEventEmitter將事件傳遞給RN頁面(RN頁面需要監(jiān)聽該事件才行)

rn拆包
拆分給common和業(yè)務(wù)包,common只包含公共的基礎(chǔ)組件,為各個(gè)業(yè)務(wù)模塊共用,可以采用內(nèi)置方案,程序啟動(dòng)時(shí)的Bridge就先加載該模塊。
業(yè)務(wù)包為各個(gè)業(yè)務(wù)模塊所獨(dú)立,打包時(shí)會(huì)根據(jù)內(nèi)部依賴將該業(yè)務(wù)模塊所依賴的組件全部導(dǎo)出,內(nèi)部會(huì)包含commom模塊的內(nèi)容,需要過濾掉,減少體積。
--manifest-output命令就是獲取各個(gè)組件的特征id值,通過對比id值實(shí)現(xiàn)過濾
下面是某個(gè)業(yè)務(wù)模塊拆包的腳本文件,shell語言編寫


#輸入ios和android
read -p "輸入platform: " -r platform
resultDir=./dist
bundlerBin=./node_modules/metro-bundler-cli/bin/metro-bundler-cli.js
bundlerCmd="$bundlerBin bundle --platform $platform --dev false"

#清空結(jié)果目錄
 if [ -e "$resultDir" ]; then
   rm -r $resultDir/*
 else
   mkdir $resultDir
 fi

#打包c(diǎn)ommon組件,目的是獲取common的特征值。 --manifest-output獲取common組件的特征id值base.manifest.json文件
$bundlerCmd --entry-file ./base.js --bundle-output $resultDir/base.jsbundle --manifest-output $resultDir/base.manifest.json --use-stable-id true

#打包業(yè)務(wù)組件    --exclude為過濾命令,根據(jù)base.manifest.json文件,過濾掉業(yè)務(wù)組件中所包含的common組件
$bundlerCmd --entry-file pax_index.js --bundle-output $resultDir/pax.jsbundle --manifest-output $resultDir/business.manifest.json --assets-dest $resultDir --exclude $resultDir/base.manifest.json  --use-stable-id true

#壓縮到目標(biāo)文件,該文件用來給APP下載熱更新,并且替換APP本地文件
cd $resultDir
if [[ "$platform" = "ios"  ]]; then
    cp ../switch.json switch.json
    zip -r paxIos.zip pax.jsbundle assets switch.json
fi
else
    cp ../switch.json ./switch.json
    zip -r paxAndroid.zip pax.jsbundle drawable-mdpi switch.jsonfi

程序運(yùn)行時(shí)需要將common和業(yè)務(wù)模塊合并,可以采用算法將jsbudle合并在執(zhí)行,也可以采用更簡單的方式,Bridge創(chuàng)建時(shí)先加載common內(nèi)容,當(dāng)進(jìn)入具體的某個(gè)業(yè)務(wù)模塊時(shí),動(dòng)態(tài)加載業(yè)務(wù)模塊jsbudle。動(dòng)態(tài)加載方法是enqueueApplicationScript,參考尾部鏈接

自建熱更新
rn具有內(nèi)置包以及存儲(chǔ)在沙盒cache中的網(wǎng)絡(luò)下載包。優(yōu)先使用cache中的熱文件,若cache中沒有需要的文件,則將內(nèi)置包拷貝到cache中。
每次打開app時(shí)從服務(wù)器拉取所有模塊的配置表,該接口需要傳的參數(shù)是一個(gè)數(shù)組,內(nèi)部表明各個(gè)模塊的當(dāng)前版本號(hào),服務(wù)器拿著版本號(hào)做對比判斷哪些模塊需要更新??蛻舳藢π枰碌哪K一一下載,然后覆蓋到cache中。若某個(gè)模塊需要回滾,則客戶端會(huì)刪除該模塊在cache中的文件。

引用:http://www.itdecent.cn/p/8711c241a9b8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

原理:http://www.itdecent.cn/p/203b91a77174

RN內(nèi)置包無效問題:
因?yàn)槊看味际菑腸ache目錄讀取js文件,所以即使APP更新后,其內(nèi)置的js包也是無效的,也即APP更新后首次打開APP還是看到以前舊的RN頁面,只有等線上的RN下載完畢,更新cache目錄下的js包,打開APP才能看到最新的RN版本。
此外還有一個(gè)隱藏的bug,如新版本RN包中新增一個(gè)頁面A,需要在新版本APP中直接跳到A頁面,那么首次更新APP時(shí)從原生跳轉(zhuǎn)到A頁面時(shí)會(huì)crash,因?yàn)榇藭r(shí)APP加載的還是cache目錄下舊的js包,并沒有A頁面,只有等線上js包下載完成覆蓋cache才會(huì)正常
解決:存儲(chǔ)當(dāng)前內(nèi)置的各個(gè)模塊js文件的md5值,一旦發(fā)現(xiàn)APP有更新,則讀取最新的內(nèi)置js文件md5,跟上次保存的做對比。若發(fā)現(xiàn)不一樣,則說明有更新內(nèi)置包,拷貝內(nèi)置包到cache目錄中覆蓋該模塊,使內(nèi)置js包即使更新。

RN實(shí)現(xiàn)圓環(huán)漸變色
畫出同一中心點(diǎn)兩段圓弧,例如100半徑和98半徑的,然后將其path封閉相連,則得到一個(gè)寬度為2的弧形矩形,利用Shape的fill可以填充系統(tǒng)的漸變色LinearGradient而實(shí)現(xiàn)圓環(huán)漸變色。但是漸變色不支持安卓

因?yàn)锳RT中的LinearGradient在安卓上無效,漸變色可使用三方框架,使用react-native-linear-gradient原生渲染,則可如下實(shí)現(xiàn)。同一個(gè)中點(diǎn)畫一個(gè)帶漸變色的100圓餅,和一個(gè)純色的98的圓餅,則得到一個(gè)寬度為2的漸變色圓環(huán)。這種圓環(huán)只能從一側(cè)漸變色到另外一側(cè),若想優(yōu)化可以采用多個(gè)漸變色圓餅拼裝,實(shí)現(xiàn)隨著圓弧的漸變色。
再得到的漸變色圓環(huán)上面,采用ART.Shape覆蓋住一段均勻顏色的圓弧,比如180度圓弧,則得到了進(jìn)度為50%的漸變色圓弧。
Shape的d屬性path繪制舉例如下:
// move: 100,100, 最初的定位點(diǎn)// arc: -20,20, 弧線的終點(diǎn),是相對上面的100,100的相對偏移點(diǎn)// arc:100,0,true,100是這段圓弧的半徑,0沒發(fā)現(xiàn)有什么用,別設(shè)置太大太小即可。true控制圓弧的方向let path = new Path().moveTo(100,100).arc(-20,20,100,0,true);

背景: 原生控制器,RN(0.5版)頁面作為視圖,視圖只有一個(gè)ScrollView,內(nèi)部多個(gè)Text撐開使ScrollView能上下滑動(dòng)的頁面。
現(xiàn)象:某些安卓手機(jī)push進(jìn)該頁面時(shí)經(jīng)常出現(xiàn)無法滑動(dòng)現(xiàn)象,但是用手機(jī)連上電腦wifi調(diào)試則一切正常,打包后異常。

代碼本身肯定沒有問題,在ios手機(jī)和多款安卓上均運(yùn)行正常,發(fā)現(xiàn)有vivo7.1,錘子8.1有上述異常
猜測代碼某些格式在這種手機(jī)上不支持,多方修改代碼,打包,測試,發(fā)現(xiàn)當(dāng)ScrollView內(nèi)部只用兩個(gè)Text包裹大量文字時(shí)正常,一旦超過4個(gè)Text包裹這些文字則容易出現(xiàn)異常,不是代碼問題,猜測是RN的一個(gè)bug

原因猜測(瞎猜):push時(shí)主線程在做動(dòng)畫,同時(shí)js線程讀取js代碼提交到主線程做渲染,若ScrollView內(nèi)部有大量Text文本,因渲染文本很耗費(fèi)資源,此時(shí)主線程任務(wù)量太大導(dǎo)致某些異常出現(xiàn),如Text文本高度計(jì)算延后,導(dǎo)致ScrollView沒有被撐開無法滑動(dòng)。手機(jī)連上電腦調(diào)試時(shí),因?yàn)槭莇ebug模式,js線程執(zhí)行緩慢,當(dāng)js內(nèi)容提交給主線程渲染時(shí)push動(dòng)畫已完成,正常。

解決:使用定時(shí)器將頁面渲染延后執(zhí)行,具體就是

componentDidMount() {    setTimeout(() => {        this.setState({            flag: true        })    },100)}

render() {    if (!this.state.flag) return null;    return <ScrollView>}

flatlist優(yōu)化:
1、getItemLayout設(shè)置,避免渲染cell時(shí)計(jì)算單元行高度
2、cell使用PureComponent,避免每次刷新所有cell都刷新了,局部刷新使用shouldComponentUpdate調(diào)節(jié)
3、keyExtractor,F(xiàn)latList的原理是往一個(gè)ScrollView依次存放所有的cell組件作為子組件,兄弟組件之間需要使用一個(gè)唯一的key來標(biāo)記自身,應(yīng)該唯一,若使用索引作為keyExtractor,要保證cell不會(huì)動(dòng)態(tài)刪除,移動(dòng)等,否則keyExtractor會(huì)重復(fù),性能降低

RN原理:
http://szuwest.github.io/react-nativekuang-jia-yuan-ma-xue-xi-iosxia.html
http://blog.cnbang.net/tech/2698/

RN幀動(dòng)畫
采用定時(shí)器不斷循環(huán)setState更改Image的source實(shí)現(xiàn)幀動(dòng)畫,安卓上面會(huì)出現(xiàn)圖片閃爍現(xiàn)象。目測是圖片刷新時(shí)安卓會(huì)先清空圖片內(nèi)容,再加載圖片并將新的圖片渲染出來,這中間存在一個(gè)間隔時(shí)間,期間圖片內(nèi)容為空,導(dǎo)致圖片先白一下(圖片背景色)再出現(xiàn)圖片內(nèi)容的閃爍現(xiàn)象
通過測試,發(fā)現(xiàn)當(dāng)幀動(dòng)畫的圖片數(shù)量較少,圖片尺寸較小時(shí),閃爍現(xiàn)象只會(huì)循環(huán)一輪,下一輪幀動(dòng)畫時(shí)就會(huì)正常。推測是因?yàn)閳D片較少時(shí),第一輪幀動(dòng)畫將所有的圖片緩存在內(nèi)存中,后續(xù)圖片直接從內(nèi)存加載速度很快從而沒有出現(xiàn)閃爍現(xiàn)象。圖片較多時(shí)幀動(dòng)畫會(huì)一直閃爍。
解決:
1、使用GIF,缺陷:gif較大時(shí),如2M,則首次初始化gif時(shí)會(huì)出現(xiàn)明顯卡頓,因?yàn)間if初始化解壓消耗大量線程資源
2、在目標(biāo)Image后面再放一張Image,該Image也使用setState同步實(shí)現(xiàn)幀動(dòng)畫,但是圖片的索引-1,這樣,當(dāng)前面那個(gè)Image刷新時(shí)看到的是后面那個(gè)Image,也就是上一幀的圖片,閃爍消除。為保險(xiǎn)起見,背景采用首幀圖片,這樣即使閃爍也肉眼難辨

幀動(dòng)畫時(shí)存在大量setState操作,性能不佳,采用setNativeProps會(huì)好很多。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容