由于业务上的需要,我们业务线接到需求要将部分页面进行 RN 的改造,很开心的接到了这个任务,一心欢喜的觉得可以学点新东西,然而所谓的 write once use anywhere 并不是那么简单。
首先网上关于 RN 基础环境搭建的文章一搜一大堆,再加上我司我对于 RN 本身进行了二次开发和一些优化,所以部分场景有所不同,防止造成误导,这里就不在进行介绍了。
本文主要涉及从学习 RN 到我们业务线 RN 成熟版本上线过程中遇到的问题。
语言了解
在了解了最新的一些基本语法和特性之后,我们就可初步进行开发了。
在开发过程中,我们发现因为 JS 是弱类型语言,所以我们在一开始写的时候,就直接将服务器返回的 json 对象作为对象一直向下的传递。但是这个过程体验极差,因为这里需要考虑如果将来服务端改字段名,是否需要全局搜索进行更改(在我看来这样的方式极为低效),而且涉及到合作的时候,你传递一个 json 对象,让接收参数开发 UI 的同学一脸懵逼,这个 JSON 里的字段都用来做什么?
对于客户端开发的同学,举个很简单的例子解释这个问题,界面间传递参数或者 service 回调回来参数都是 dictionary 那么后续的开发和维护成本比起传递都是 model 在维护和开发成本上差距都是巨大的。
在这个时候,我们向前端的同学请教了相关的问题。得到答复是,他们一般在开发的过程中一般的解决方案大概代码如下
let model = { param1 = serverJson.Param1, param2 = serverJson.Param2, }
然后将转换后的 model 进行传递,这样的方式解决了服务端字段发生改变需要全局搜索进行修改的问题,但是并没有解决 json 对象传递代码可读性差和维护成本高的问题
最后我们同时选择了 Flow 和比较好的 RN 插件 prop-types
来做辅助。
于是乎我们代码就成了下边的样子
static propTypes = {
param1: PropTypes.number,
param2:PropTypes.number,
data:PropTypes.array,
array:PropTypes.array,
model:PropTypes.objectOf(Model)
}
scrollToIndex(params: {
animated?: ?boolean,
index: number,
viewOffset?: number,
viewPosition?: number,
}) {
}
这样在可读性和可维护性方面都得到了极大的提升。我一直认为这样的调研极为重要,因为这对于后续的开发极效率极为必要!!!
基本组件
事件处理
在开发的过程中,我们发现封装的小的 view 组件事件的向上传递问题和客户端使用 delegate 一直向上传递很相似,层层传递写起来不简洁。感觉做了很多堆砌的工作,因为之前对于 Vue
有一定的了解。第一时间想到了 Redux , 但是组里的同学对于 Redux 并没有过了解。担心 Redux 的学习成本,但是我们沟通了这个问题之后,基本使用组里同学很快就基本掌握。
在客户端开发过程中,我们部分场景也放弃了事件层层回调的 delegate 或者 block 的方案。我们使用了苹果在 UIControl 中更为常见的事件处理模式 Target-Action 。 有兴趣的朋友可以尝试下,希望能理解其中的不同和为什么苹果会使用 Target-Action 来设计 UIControl 来设计事件的传递。
调用原生
因为 RN 本身提供的能力有限,比如数据的缓存,SDWebImage,数据库等都需要原生进行实现。这个时候就需要我们在原生进行实现。相关的文章很多,这里暂不做扩展。但是相关的知识的学习很重要。
性能优化
因为我们第一期 RN 化涉及到的页面不是很多,所以相关的经验并不是很多。下边只是简单的介绍,其实 RN 现在依然存在很多的问题,写出了原生类似的效果并不意味着真的能替代原生,在 RN 端还是需要很多优化。
我们在开发过程中遇到的问题大致有如下。
RN 的 scroll 回调并不是连续性的,因此如果根据试图滚动的 contentOffSet 来调整其它试图的位置。存在严重的丢帧现象,具体原因在 RN 的 issue 中查找。对于这个问题,我们当前的解决方案是找 UI 同学更改了交互效果。其实更好的解决方案是调用原生方案进行解决,但是我们的基础组件部门写的原生方案同样存在很严重的性能问题,所以暂时也放弃了。因为时间紧迫,也没有在做深入研究。之后会有后续研究。
RN 原生的 Image 是不存在 placeHold 概念的。想写出 placeHold 的效果,还是需要调用原声。
当然上边的方法虽然很大程度上解决了内存暴涨的问题,但是同时带来了新的问题,就是滑动过程中,每个 cell 的图片是重复加载的,这又大大的消耗这用户的流量。于是又要封装原生的 imageView 来替代当前 image 组件。(主要为了 SDWebImage 和 Fresco 的功能)
同时对于 RN 来说做图片和数据的懒加载都比原生相比麻烦一些,但是在开发过程中懒加载一定是一个要经常考虑的问题才能更好的优化程序的性能。
除此之外还有动画等等的坑也是一点一点走过,RN 虽然是多端复用,但是确实存在一些弊病,对于替代原生的想法,我认为还有很长的路要走。优化这里就不说更多了,因为很多问题和场景还是要在实际的开发中去发现和解决问题的。
其他相关知识
在网络请求部分,对于网络请求层还要学习 Promise 的用法和相关知识。
打包、拆包、发布
因为这一块基础数据平台已经为我们开发好了,所以我们每次发布只是在后台管理系统上进行简单的点击就能完成,这里不做详细展开,后续会进行详细的了解并进行说明。
我一直认为 CI 是提高程序开发效率的必备工具,所以虽然当前对于此不甚了解,也将此项写上,希望大家都可以对于这一部分有足够的重视。