简单地从前端工程师和系统整体角度说一下React native的特点和优劣吧。
react native充分利用了Facebook的现有轮子,是一个很优秀的集成作品,并且我相信这个团队对前端的了解很深刻,否则不可能让Native code「退居二线」。
对应到前端开发,整个系统结构是这样:
JSX vs HTML
CSS-layout vs css
ECMAScript 6 vs ECMAScript 5
React native View vs DOM
无需编译,我在第一次编译了ipa装好以后,就再也没更新过app,只要更新云端的js代码,reload一下,整个界面就全变了。
多数布局代码都是JSX,所有Native组件都是标签化的XML,这对于前端程序员来说,降低了不少学习成本,也大大减少了代码量,不信你可以看看JSX编译后的代码。
复用React系统,也减少了一定学习和开发成本,更重要的是利用了React里面的分层和diff机制。js层传给Native层的是一个diff后的json,然后由Native将这个数据映射成真正的布局视图。
css-layout也是点睛之笔,前端可以继续用熟悉的类css方式来编写布局,通过这个工具转换成constrain布局。
系统只有js-objc的单向调用,就是把原生UI组件的方法通过javascritcore或者webview(低版本iOS)映射到js中来,整个调用过程是异步的,这样的设计令React native可以让js运行在桌面chrome中,通过websocket连接Native code和桌面chrome,极大地方便了调试。对其中的机制Bang的一篇文章写得很详细,我就不拾人牙慧了:http://blog.cnbang.net/tech/2698/
。但这样设计也会带来一些问题,后面说。
点按操作也被抽象成了一组组件(TouchableXXX),这种抽象方式是我在之前做类似工作中没有想到的。facebook还列出Native为什么和web「手感」不同的原因:实时的点按反馈和取消能力。http://facebook.github.io/react-native/docs/gesture-responder-system.html#content
这套相应机制设计得很完善,能像Native code那样控制整个点按操作的所有过程。
Debug相当方便!修改了js以后,通过内建的nodejs watcher编译成bundle,在模拟器里面按cmd+r就可以看到效果。而且按cmd+d,可以打开一个chrome窗口,所有的js都移到了chrome里面运行,所以什么断点单步打调用栈,都不在话下。
上面的既是特点也是优点,下面说说缺点,或者应该说:「仍然遗留的问题」,在我看来,这个方案已经超越了Hybird方案。
系统仍然(不得不)依赖原生组件暴露出来的组件和方法。举两个例子,ScrollView这个组件,在Native层是有大量事件的,scrollViewWillBeginDragging, scrollViewWillEndDragging,scrollViewDidEndDragging等等,这些事件在现有的版本都没有暴露,基本上做不了组件联动效果。另外,这个版本中有大量组件是iOS only的:ActivityIndicatorIOS、DatePickerIOS、NavigatorIOS、PickerIOS、SliderIOS、SwitchIOS、TabBarIOS、AlertIOS、AppStateIOS、LinkingIOS、PushNotificationIOS、StatusBarIOS、VibrationIOS,反过来看,剩余的都是一些抽象程度极强的基本组件。这样,用户必须在不同的平台下写两套代码,而且所有能力仍然强烈依赖 React native 开发人员暴露的接口。
由于最外层是React,初次学习成本高,不像往常的Hybird方案,只要多学几个JS API就可以开始干活了。当然,React的确让后续开发变得简单了一些,这么一套外来的(基于iOS)、残缺不全的(css-layout)在React的包装下,的确显得不那么面目可憎了。
另外,React Native仍然很不完善。文档还不全,我基本上是看着他的示例代码完成的demo,集成到已有app的文档也是今天才出来。按照官方的说法,Android版本要到半年后才发布: http://facebook.github.io/react/blog/#when-is-react-native-android-coming
,届时整个系统设计可能还会有很大的变化。
PS,在使用Tabbar的时候,我惊喜的发现他们居然用了iconfont方案,我现在手头的项目中也有同样的实现,不过API怎么设计一直很头疼。结果,我发现他是这么写的:
<TabBarItemIOS
name="blueTab"
icon={_ix_DEPRECATED('favorites')}
....>
在 _ix_DEPRECATED 的定义处,有一句注释: // TODO(nicklockwood): How can this fit our require system?
HOW?
以上。