使用ReactNative的心得

适配iPhoneX

RN版本0.52之后提供了适配iPhoneX的组件SafeView。不过单独这个是不行的,还需要在ios中修改配置,把视图从一个短小的区域拉伸到全屏的大小。
enter image description here

这里通过修改设置打开默认的安全区域。
enter image description here

由于之前使用的还是旧版的RN,这里我为了兼容旧的版本做了一个js的判断。通过判断高度是否符合812来判断是否iPhoneX。同时有一个小小的缓存,不需要每次都重复判断。这里的1.0.6是开始使用新能力的版本号。
enter image description here

添加额外的线程

有些功能其实没必要跑在UI线程上。这些东西如果放在组件里反而不是那么融洽。甚至有时候会对正常的逻辑产生影响。

可以使用下面的方式注册一下额外的层。这个不显示UI,但是可以用来更新一些缓存,返回远程数据等。

1
2
3
AppRegistry.registerRunnable('RunableTask', TaskRun)

AppRegistry.runApplication('RunableTask', {});

在线上产品中就是利用了这一个层做了一些额外的事情。这里我使用事件触发的形式来做正常组件和这一个层的通知。
enter image description here

需要小心一点。如果在这一层做了定时器、循环事件等操作,记得要取消掉,不然事件就会变成两次。

缓存

APP还是需要缓存的。这里可以缓存一些上次打开的数据,比如广告、用户信息等。

在打开APP的时候可以先用这些数据走正常的流程,然后在用一个异步的任务去鉴定、更新这些数据。这样下来可以让APP打开非常流畅,同时用户也不会发现数据变化大等异常。这些同时也是需要后端接口数据支持的。

关于Alert、Modal

正常情况下Alert、Modal是独立于当前组件View之上的。如果这个时候遇到意外情况。比如组件销毁、暂停等情况下Alert还未销毁。这个时候就会发生比较严重的错误。

Alert大多数会报错,APP闪退。

Modal部分会报错,部分会暂停,失去事件等操作。导致APP一直停留在Modal视图上,用户也不能操作任何东西。时间长了系统就会判断APP未响应等等。

如果你不想处理这些东西,可以考虑使用一个自定义的Alert或者内嵌在组件中的View来代替Modal。

自定义组件

在APP中其实有些属性是要经常用到的。比如Text组件的禁止使用系统字体大小,Image的缩放方式等。这些组件在平常使用过程中会经常重复添加各种属性,可以将这些组件独立出来,并且使用更加语义化的属性名来代替RN提供的使用方式。

在这个的基础上还可以将按钮、卡片等组件进一步抽象出来。对于不使用第三方开源组件的项目来说还是很有必要的。

解决遇到的问题

使用RN开发会遇到很多问题,这些问题都可以在RN的Issues中找到答案。如果还没有就上google去搜一下,这个要求使用科学上网的形式。

有些问题需要修改RN的代码。不要怕麻烦,如果是js部分的修改,直接将下载的包修改成可上传的包就行了。这里记得上传到私有npm库中。如果是native的问题最好是在自己的native代码中覆盖掉旧的代码,毕竟前端去编译RN的源代码还是有很大的风险的。

不要去百度,百度真的没有答案。

按钮

RN提供的按钮其实很丑,正常开发的时候大家都是使用自定义的按钮。
enter image description here

使用这种模式做出来的按钮非常漂亮,也更能符合设计的结果。不过使用的时候尽量不要给按钮本身加样式,有样式尽量添加到内部的View等组件上。

向下兼容

RN使用的过程中我们升级了一个大的版本,从0.40系列升级到了0.50系列。由于大部分手机用户还存在不愿意升级APP的情况,向下兼容成了唯一的选择。

我使用的策略是修改源代码。。。。

比如升级0.53的时候发现有些native组件名变了。原来使用的是RCTMultilineTextInputView,现在变成了RCTTextView。不管RN出于什么理由改变了这个组件名字,造成的结果就是现在的旧代码不能跑在新的APP壳下。

我们可以打印出NativeModules的UIManager对象看看。
enter image description here

而兼容也是从这里开始做的。我们判断一下当前的RN是否在UIManager中提供了对应的原生组件即可判断当前的环境是否正确的环境。

比如要升级到53,修改53的源代码react-native/Libraries/Components/TextInput/TextInput.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//安卓的没变化,要排除
if (Platform.OS === 'android') {
var AndroidTextInput = requireNativeComponent('AndroidTextInput', null);
} else if (Platform.OS === 'ios') {
//如果支持RCTTextView,既新APP
if(UIManager.RCTTextView){
var RCTMultilineTextInputView = requireNativeComponent('RCTTextView', null);
var RCTSinglelineTextInputView = requireNativeComponent('RCTTextField', null);
}else{
//其他情况
var RCTMultilineTextInputView = requireNativeComponent('RCTMultilineTextInputView', null);
var RCTSinglelineTextInputView = requireNativeComponent('RCTSinglelineTextInputView', null);
}
}

使用类似这样的手段就能区别两种APP壳的环境。用户在使用的时候也不至于要必须升级APP才能使用新版APP的功能了。

使用RN开发APP确实非常快,但是各位在开发中还是不要忘记钻研RN的源代码。很多解决方案其实很简单,有些时候可能只是由于低版本的APP不支持而导致的。

如果你想对RN有一个进一步的了解,还需要对原生的代码也有一定的了解。当然正常情况下还是有位这方面的同事一起开发比较好。

请支持我一下吧.