React Native 实践与感悟

来自:tooyoungt

移动开发的发展渐渐趋于成熟,开发者的技能树分布渐渐完善。随着大前端的发展跨平台技术也衍生除了相关平台。对于移动开发者来说,也是面临着新的机遇与挑战,各个公司也尝试拥抱新技术,可以说这也是一个趋势相关的挑战。由于公司产品,存在Android,iOS两组开发人员,且业务逻辑与UI几无差别。对于成本和效率的考虑团队开始考虑使用React Native 开发产品。

开始前准备

RN的开发语言基于ES6,整体框架基于React 实现。所以开发RN必须掌握 ES6和React,这两者就不在此文讨论范围了。值得一说的是,之前开发android ,从17年google把kotlin提升到官方语言之后,就开始使用,其中一些语言与思想跟ES6相似,所以切换到ES6开发,还是很爽的。并且ES6有很多的语法糖,用起来甚是很6。跟ES5相比有增加了很多语法,对于java开发者来说熟悉很多,准守规范不至于入坑。如果使用TypeScript那就更熟悉了。React之前没有接触过,但是开发RN那是必须要熟悉的。看了看简单的使用文档对于Component,Props,State,JSX都要有基本的熟悉,大概就可以开始使用了。

快速开始

能跑起一个'Hello World'大概是学习一项新技术开始。这是对环境以及相关基本的配置成功的一种标志。怎么开始呢?当然是找到官方文档,里面有相关介绍。(多说一句,如果一项技术没有完善文档,真的不值得使用)文档首选官网,那里是有最新最详细的介绍和使用。不过是英文的对于国内很多人来说,比如我也是很有障碍的。所幸有中文文章,虽然跟官方文档比起来,比较过时,很多没有翻译的到位。有些也确实,但对于我们的简单开始是够用的了。不得不说React Native中文网,的对于如何搭建开发环境是很详细的,也考虑到了国内由于墙的存在产生的一些问题。照着文档来,并且保证自己可翻墙,没有碰到什么问题。通过 react-native init awesome project 生成第一个项目,然后react-native run-android 跑起来,成功的一刻当然是很开心的。不过还好,因为早早在15年rn刚开始出的时候我就已经试过了,不过那时候我才刚刚入行android。技术也不行,并且也没有觉得RN能怎样,学习成本对于我来说也高,毕竟android都还没有整明白。也就没有继续下去,说起来还是自己拖延,执行力低,并且也没有明确的规划。后面RN也是发展的越来越成熟,但是国内应用的还是很少,到去年国外很多大公司开始宣布弃用React Native,这又是另一个话题了。

React native 的能力

能跑起来'hello world'只是一小步,接下来还面临着星辰大海。要想走得更远我们就要确定RN的极限在哪儿。对于这一点就要弄清楚RN的原理,这一点对于现在的我来说,谈这个有点不足够。通过在Android上执行adb shell dumpsys activity top.查看一个简单页面的原生堆栈。可以看到RN封装了各个组件。就拿Image来说,最后显示在Android上的是ReactImageView,又是继承自DraweeView。所以传递给Image的属性最终传递给了DraweeView了。这也就是React Native两个单词的含义了吧。

这如何传递,以及js,与native之间的双向通信暂且不讨论。可以看到,通过这种对原生组件的封装可以说RN能做到几乎所有原生可以做到的。这里可能会问,原生自定义View呢?这就是RN厉害的一点了,我们可以重用已经有的自定义View。通过RN的预留接口,只需要先定义好需要暴露的属性,然后通过几个步骤就可以实现在RN中调用自定义View了。这个能力真的是强。也许还会问,怎么实现高性能代码呢,比如多线程?众所周知,js是单线程模型,虽然ES6实现异步也有好几种方式,但是跟原生比相比还是差的。这之间的差距就涉及到我知识的盲区了。同样的RN也提供了给我们接口实现,我们可以编写原生代码,然后定义好接口,通过RN提供的接口暴露出去。就可以在RN中调用原生模块代码,同时由于通信是双向的,所以原生也可传递给RN。也就是几乎不存在实现不了的情况。作为例子可以编写一个Toast模块通过实现RN提供的接口封装Toast,实现RN中调用我们自己实现的Toast组件,这个在官方文档上有完整demo存在。

但这个过程还是很繁琐的,如果模块很复杂就要考虑到很多架构上的实现。这样就对原生开发能力有一定要求,但这种需求毕竟是少数,并且到如今生态已经很完整,很多第三方库,sdk等都推出了RN版本,已经定义好了接口给RN调用。以上确定了RN与原生之间的交互补助了RN的短板。那么RN本身可以在不依赖于原生的极限能力又有那些呢?前文提到,RN最后提供的都是原生组件。那么RN能多大程度上不依赖于原生,仅仅通过自身实现各种交互效果呢,还有性能怎样呢?九宫格显示图片,是非常常用的一个控件。通过对不同数量的图片,在限制的区域内,布局并动态的调整大小。在Android开发中,一般来说通过自定义ViewGroup,在onMeasure中实现调整算法,并对每个子view进行测量。再在onLayout 在确定算法,并且layout每一个子View到指定位置即可实现。当然最后还要考虑到加载图片,以及定义属性等问题。在RN中整体的思路是一致的只是很多步骤不再需要了。首先计算如何根据图片数量调整布局位置和每个Image的大小。拿到大小,Android中是把大小传递给ImageView#onMeasure,在RN中则指定style中的width,height.剩下的就是layout了。这一点有所不同,RN采用css标准布局方式,支持flex布局。所以我们是按照RN中定义的布局方式布局,这样就可以了。剩下的图片加载,则直接定义Image加载图片的属性就可以了。整个过程效率是很高的,并且是逻辑清晰的,最后执行的效果也不错。通过这个例子可以知道RN实现普通的或者一些复杂的效果是完全可以的,性能上也能够得到很好的解决。也许会说手势,动画对于RN来说怎么样,动画对RN来说一直都是个影响性能很关键的一点,特别是在Android中。RN提供了相关的api来实现,因为我也没有很深入的去测量具体性能怎样,所以无法给出性能相关的结论。不过这些api常用功能还是实现的没问题的,毕竟是对于原生功能的封装。我想,通过以上的描述可以对RN做一个总结,对于普通业务场景中的开发RN是完全HOLD住的,对于需要高性能Native编程,Native也完全支持,对于Native已有组件RN也还是没问题。所以RN能办得到比我们想像得更多的事儿。

生态与框架

从2015年RN开源到如今,已经走过了四个年头。随着社区中开发者不断的努力,现在的RN早已不是当初一堆坑的RN了。在我面前的是成熟,焕发着无限能力的RN。这一切都离不开RN的整个生态和第三库。打开github的 awesome-react-native,可以看到翻不到底的项目。这些项目都是开发者的努力,也是我们可以使用并借鉴的。正是由于这些项目,RN才可以达到现有的成熟和效率。对于一个应用来说,路由始终是一个绕不过去的关键问题。在web中,很简单,仅仅通过标签的href属性就可以实现跳转。Android中通过Intent也很简单。但是在RN中情况就复杂很多了,早期并没有很好的解决方案,通过社区的努力 React-Navigation诞生了。现在已经到3.x版本。可以很方便的实现页面之间的路由。像这样帮助开发的开源项目还有很多例如Redux等。共同支撑起来RN的生态。

项目实战

在实践中学习,我一直认为是掌握一门技术的最好方式。在学习中我也实现了一个gank.io的RN版本。总得来说在这个过程中把各个RN中的知识点都过了一遍,也形成了一套开发套路,也对RN项目的理解更深了。RN基于状态管理,这一点对于开发业务来说还是很方便的。规划好了状态,业务逻辑清晰基本的实现基本没有问题。如果项目大起来,状态的管理会导致效率的降低,这时候通过Redux是很必要的。对于组件的状态封装一个下拉刷新上拉加载的组件,是一个很好的例子。这个组件需要有 正在刷新,可以加载,错误,加载完成等状态,实现的细节不多描述。不同的状态展示不同的UI真的是很容易。react-navigation 虽然功能强大,但我用着还是不爽,可能是还没有用熟悉吧。项目的架构,参考了github上成熟的开源项目,这一点跟android项目其实没差,大概可以按照相同的方式组织代码。不过原则还是要与一个统一的规范。剩下的就是业务逻辑了,这也是一个程序的内容和功能所在。业务逻辑其实是没多大差别,只要想好了实现步骤。不过具体的实现肯定是有差的。在RN中,就很爽fetch函数返回的Promise对象那可是方便。而且通过State状态管理,很方便的切换各个状态,再借助生态中提供的一些库,可以说只要不是太复杂的业务。实现起来难度并不高。总体而言实现一个展示类的App用RN真的爽。如果细节一些我想需要考虑的问题还会比较多,比如对Android中机型的适配,如何编写高性能的代码,性能管理等。

参考资料

官方文档

awesome react native

推荐↓↓↓
安卓开发
上一篇:尝试加载一千张照片 下一篇:对于 Android 业务开发的一些理解总结