一个前端用 React Native 开发首个 iOS App 后的心得分享

6,490 阅读8分钟
原文链接: mp.weixin.qq.com

版权声明

作者:Tom Tang,目前任职于HireArt,负责移动开发业务

译者:刘振涛

本文由原作者授权翻译并发布,本文首发于移动开发前线公众号,未经许可禁止转载。

编者的话我询问过不少资深的移动开发者对于React Native的看法,他们大多不太喜欢,并不认为它能做什么大事。不过,如果从另一边的前端的眼中看,React Native为他们打通了移动开发的最后一片圣域:原生应用,可以说寄托了他们的期待。本文作者之前没有Objective-C和Swift的经验,使用React Native开发了首个iOS App之后,写下了这篇心得感受,包括React Native的正面与负面意见,以及他们遇到的一些坑。但最终他达成了预期目标,并对React Native感到满意。作为移动开发者,看到这篇文章,可能会百味杂陈吧。

下面为正文:

我们想为用户设计一款移动端的应用,却不知从何下手,我们只知道每一个人都希望做一款又酷又好玩儿体验又十分顺滑的应用,然而团队里没人有移动端的经验。

于是,我们最终只好选择React Native作为我们的开发工具。结果证明,这是一个非常明智的选择,我们从开始到现在的所思所感,全都总结如下:

为什么要用React Native

我 们是一群Web开发者,而不是iOS开发者。我曾参加过几个在纽约举办的有关Swift和Objective-C的线下聚会,但最后我依然认为编写 Ruby和JavaScript代码最令我愉悦。我们团队在2015年初开始使用Facebook的React框架并取得了初步成效,React Native面世后,我们一度怀疑像这样的交叉设备平台会有很多潜在的问题。但是随着我们的研究深入,我们越发喜欢它了:


  • 一次学习,随处可用交叉设备平台通常品相不佳,而且只支持不同设备间相同的功能。而React Native虽然基于React.js框架,但为Android和iOS两个平台编写的项目代码却不尽相同,它们之间只共享一部分代码。因此这些代码在每 个平台上都能调用所有原生组件,发挥其最大的效用。

  • 声明式的视图当初我们在Web平台用React编写代码的时候就已经爱上了这种声明式的视图,用React Native在iOS平台开发延续了这一传统,如此一来,我们的代码就变得可预测且bug更少。

  • 为移动平台设计的Flexbox(弹性盒模型) 我们不了解iOS布局约束求解器的工作原理,但幸运的是,React Native引入了大部分浏览器都支持的Flexbox以使布局的过程变得更直观。


iOS约束器(Constraints)


Flexbox

  • 用JavaScript编写代码构建移动应用完全是我们未知的领域,显而易见,如果我们用已掌握的语言来编写代码会节省非常多的时间。况且,我们曾经痴迷于CoffeeScript优雅的语法,而现在React Native已经默认支持了ES6,这让我们激动不已,因为我们可以很轻松地过渡到新的语法体系中。

不用React Native的几个保留意见

我们深知节省下来的时间再多也抵不过捉襟见肘的可定制性和有限可用的React Native组件。我们也曾犹豫过是否一定要是用React Native,毕竟以下几条理由确实值得仔细琢磨:

  • React Native生态系统的限制性2015年9月,我们刚开始研究React Native,彼时非常多的iOS原生组件已经被实现出来,而且还有更多的功能正紧锣密鼓地开发当中。然而,我们还是会担心React Native最终不支持某些我们非常需要的组件,如此一来我们就只能在React Native桥接器的基础上构建其它相关的SDK了(例如提供对AWS和Mixpanel的支持)。

  • 太前沿React Native更新非常快,支持老版本的代码有可能(极少数情况下)在新版本中就被废除。我们在过往的开发周期中遇到过几次这类问题,最后我们不得不作出这样的决定:当且只当亟需某些经过严格测试的新特性时才会主动升级。

  • Google搜索到的资料少之又少为一个新系统编写代码意味着很有可能遇到前人没经历过的错误,这些无法通过搜索得到解决方案的问题远比我们编写Ruby on Rails代码的时候要多。想要找到这些问题的解决方案需要足够多的韧劲儿:在文档中定位问题,在源代码中挖掘可能的漏洞。不管怎样,对于React Native团队和它的生态系统而言,只有更多地解决此类问题,多发布一些常规修订才能给他们带来更好的信誉。

React Native的包管理

事实证明,支持React Native的组件简直多到爆炸。无论是ActivityIndicator(加载中指示器)、Alert(警告框)还是Slide(轮播),这些组件与 JavaScript中的同类组件并无二异。我无法用语言描述在不了解Objective C和Swift的前提下开发原生iOS应用有多么省心。此外,npm上每天都会出现许多新的代码包,以下这些我们都很喜欢(排名不分先后):

react-native-simple-store 我们刚开始用的是AsyncStorage,但却不得不一遍又一遍地重复构建相同的save和get函数。Simple Store是一个基于AsyncStorage的解决方案,它十分出色,可以分分钟连接到设备的存储区。


react-native-vector-icons 这是我们已知的最好的向量图标包,我们同时使用FontAwesome和EvilIcons,它们可以完美地结合。MaterialIcons、IonIcons和其它图标库均可直接通过这个包获取到。


tcomb-form-native 通过这个包可以轻松地创建表单。你可以既可以使用其默认的Input组件,也可以自定义Input类型,键盘和自动纠正等功能。


react-native-router-flux 合理的路由设计可以简化业务流程,通过一行简单的代码你就可以将定义好的路由置入视图层。

Actions.dashboard()

怪异的地方

作为Web开发人员,我们遇到了一些令人感到十分头疼的问题:

样式在React Native中可以使用样式表,但只能使用非级联的行内样式,用这种方式定义的样式非常难理解。我们可以通过行内越权的方式定义多级样式来解决这一问题。

Styles.js


Component.js


标准样式如下所示:

style={Styles.header}

自定义行内样式如下所示:

style={{color: 'white'}}

我们将二者进行了整合:

style={[Styles.header, {color: 'white'}]}

这种hack的方式让人很不爽……可能有更好的方法可以解决此类问题,但是当时我们想到这个方案的时候压根儿不了解。

循环调用/导航器你很可能在使用NavigatorIOS的时候遇到此类问题,这是很糟糕的选择(除递归外 的大多数循环都很糟糕)。Web路由是单一过程的,你可以获取到当前位置及历史位置的所有信息。而在iOS中,你需要将视图置入栈或从中取出相应视图,如 果置入一个已存在于栈中的组件将会触发错误。如果调用组件时将当前组件置入到栈中可能会引发调用循环的问题,从而导致程序中断执行。react- native-router-flux可以帮我们解决这个问题,它能用一种可伸缩的方式推导出我们使用的历史路径。

最后的话

React Native是一个优秀的框架,用它来构建移动应用是非常好的选择。由于我们不了解Swift和Objective C,很难将纯原生与React Native两种实现进行比较,单就使用体验而言,它已经可以满足绝大多数的使用场景。我们乐于见到React Native带给我们的首个移动应用,它也持续发展力图变得更加完善。最后我始终认为,对于我们这样一支敏捷灵活的开发团队而言,这项技术帮我们快速地从Web环境切换到移动应用开发领域,非常感谢!

阿里百川(baichuan.taobao.com)是阿里巴巴集团“云”+“端”的核心战略是阿里巴巴集团无线开放平台,基于世界级的后端服务和成熟的商业组件,通过“技术、商业及大数据”的开放,为移动创业者提供可快速搭建App、商业化APP并提升用户体验的解决方案;同时提供多元化的创业服务-物理空间、孵化运营、创业投资等,为移动创业者提供全面保障。

        关于阿里百川