RN使用经验

rn版本:0.55
原生和rn混编

TouchableWithoutFeedback系列组件内部包含的Text设置lineHeight时,在某些安卓手机上可能导致文本显示出现被切割现象

安卓的部分组件如Text无法撑开父视图的宽高
安卓和ios的Text组件文本内置间隙差异很大
Dimensions.get('window’)获取的屏幕宽高,在某些安卓机型上面有问题,例如没有考虑顶部状态栏和底部按键栏目,需要原生另外写方法判断

对Animated.View等动画组件,设置transform的scale为0在某些安卓手机上无法完全隐藏,可以配合设置opacity为0实现效果

rn执行的代码中涉及到原生代码有改动,则该rn包不能下发给旧的app版本,需要做版本控制

rn页面实现类似viewwillappera的代理方法
前提是所有的rn页面的跳转是由原生控制,rn仅仅是显示作用。跳转到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就是一个普通的UIViewController,在内部的viewWillAppear中发出通知,通过RCTEventEmitter将事件传递给RN页面(RN页面需要监听该事件才行)

rn拆包
拆分给common和业务包,common只包含公共的基础组件,为各个业务模块共用,可以采用内置方案,程序启动时的Bridge就先加载该模块。
业务包为各个业务模块所独立,打包时会根据内部依赖将该业务模块所依赖的组件全部导出,内部会包含commom模块的内容,需要过滤掉,减少体积。
--manifest-output命令就是获取各个组件的特征id值,通过对比id值实现过滤
下面是某个业务模块拆包的脚本文件,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"

#清空结果目录
 if [ -e "$resultDir" ]; then
   rm -r $resultDir/*
 else
   mkdir $resultDir
 fi

#打包common组件,目的是获取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

#打包业务组件    --exclude为过滤命令,根据base.manifest.json文件,过滤掉业务组件中所包含的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

#压缩到目标文件,该文件用来给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

程序运行时需要将common和业务模块合并,可以采用算法将jsbudle合并在执行,也可以采用更简单的方式,Bridge创建时先加载common内容,当进入具体的某个业务模块时,动态加载业务模块jsbudle。动态加载方法是enqueueApplicationScript,参考尾部链接

自建热更新
rn具有内置包以及存储在沙盒cache中的网络下载包。优先使用cache中的热文件,若cache中没有需要的文件,则将内置包拷贝到cache中。
每次打开app时从服务器拉取所有模块的配置表,该接口需要传的参数是一个数组,内部表明各个模块的当前版本号,服务器拿着版本号做对比判断哪些模块需要更新。客户端对需要更新的模块一一下载,然后覆盖到cache中。若某个模块需要回滚,则客户端会删除该模块在cache中的文件。

引用:https://www.jianshu.com/p/8711c241a9b8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

原理:https://www.jianshu.com/p/203b91a77174

RN内置包无效问题:
因为每次都是从cache目录读取js文件,所以即使APP更新后,其内置的js包也是无效的,也即APP更新后首次打开APP还是看到以前旧的RN页面,只有等线上的RN下载完毕,更新cache目录下的js包,打开APP才能看到最新的RN版本。
此外还有一个隐藏的bug,如新版本RN包中新增一个页面A,需要在新版本APP中直接跳到A页面,那么首次更新APP时从原生跳转到A页面时会crash,因为此时APP加载的还是cache目录下旧的js包,并没有A页面,只有等线上js包下载完成覆盖cache才会正常
解决:存储当前内置的各个模块js文件的md5值,一旦发现APP有更新,则读取最新的内置js文件md5,跟上次保存的做对比。若发现不一样,则说明有更新内置包,拷贝内置包到cache目录中覆盖该模块,使内置js包即使更新。

RN实现圆环渐变色
画出同一中心点两段圆弧,例如100半径和98半径的,然后将其path封闭相连,则得到一个宽度为2的弧形矩形,利用Shape的fill可以填充系统的渐变色LinearGradient而实现圆环渐变色。但是渐变色不支持安卓

因为ART中的LinearGradient在安卓上无效,渐变色可使用三方框架,使用react-native-linear-gradient原生渲染,则可如下实现。同一个中点画一个带渐变色的100圆饼,和一个纯色的98的圆饼,则得到一个宽度为2的渐变色圆环。这种圆环只能从一侧渐变色到另外一侧,若想优化可以采用多个渐变色圆饼拼装,实现随着圆弧的渐变色。
再得到的渐变色圆环上面,采用ART.Shape覆盖住一段均匀颜色的圆弧,比如180度圆弧,则得到了进度为50%的渐变色圆弧。
Shape的d属性path绘制举例如下:
// move: 100,100, 最初的定位点// arc: -20,20, 弧线的终点,是相对上面的100,100的相对偏移点// arc:100,0,true,100是这段圆弧的半径,0没发现有什么用,别设置太大太小即可。true控制圆弧的方向let path = new Path().moveTo(100,100).arc(-20,20,100,0,true);

背景: 原生控制器,RN(0.5版)页面作为视图,视图只有一个ScrollView,内部多个Text撑开使ScrollView能上下滑动的页面。
现象:某些安卓手机push进该页面时经常出现无法滑动现象,但是用手机连上电脑wifi调试则一切正常,打包后异常。

代码本身肯定没有问题,在ios手机和多款安卓上均运行正常,发现有vivo7.1,锤子8.1有上述异常
猜测代码某些格式在这种手机上不支持,多方修改代码,打包,测试,发现当ScrollView内部只用两个Text包裹大量文字时正常,一旦超过4个Text包裹这些文字则容易出现异常,不是代码问题,猜测是RN的一个bug

原因猜测(瞎猜):push时主线程在做动画,同时js线程读取js代码提交到主线程做渲染,若ScrollView内部有大量Text文本,因渲染文本很耗费资源,此时主线程任务量太大导致某些异常出现,如Text文本高度计算延后,导致ScrollView没有被撑开无法滑动。手机连上电脑调试时,因为是debug模式,js线程执行缓慢,当js内容提交给主线程渲染时push动画已完成,正常。

解决:使用定时器将页面渲染延后执行,具体就是

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

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

flatlist优化:
1、getItemLayout设置,避免渲染cell时计算单元行高度
2、cell使用PureComponent,避免每次刷新所有cell都刷新了,局部刷新使用shouldComponentUpdate调节
3、keyExtractor,FlatList的原理是往一个ScrollView依次存放所有的cell组件作为子组件,兄弟组件之间需要使用一个唯一的key来标记自身,应该唯一,若使用索引作为keyExtractor,要保证cell不会动态删除,移动等,否则keyExtractor会重复,性能降低

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

RN帧动画
采用定时器不断循环setState更改Image的source实现帧动画,安卓上面会出现图片闪烁现象。目测是图片刷新时安卓会先清空图片内容,再加载图片并将新的图片渲染出来,这中间存在一个间隔时间,期间图片内容为空,导致图片先白一下(图片背景色)再出现图片内容的闪烁现象
通过测试,发现当帧动画的图片数量较少,图片尺寸较小时,闪烁现象只会循环一轮,下一轮帧动画时就会正常。推测是因为图片较少时,第一轮帧动画将所有的图片缓存在内存中,后续图片直接从内存加载速度很快从而没有出现闪烁现象。图片较多时帧动画会一直闪烁。
解决:
1、使用GIF,缺陷:gif较大时,如2M,则首次初始化gif时会出现明显卡顿,因为gif初始化解压消耗大量线程资源
2、在目标Image后面再放一张Image,该Image也使用setState同步实现帧动画,但是图片的索引-1,这样,当前面那个Image刷新时看到的是后面那个Image,也就是上一帧的图片,闪烁消除。为保险起见,背景采用首帧图片,这样即使闪烁也肉眼难辨

帧动画时存在大量setState操作,性能不佳,采用setNativeProps会好很多。

你可能感兴趣的:(RN使用经验)