【译】关于React Native在专业用于多种规模项目后的思考

React Native已经存在了一段时间了。当Android支持发布时(iOS发布后大约一年),我把它用于专业。我决定投入时间进行跨平台开发。当我发现React Native时,我已是iOS开发人员已经有6年了,并且不只仅是Mac OS X开发人员。react

我在App Store和Play商店为个人客户开发了四个中等大小(不包括依赖项的10,000-20,000行代码)项目。我还负责监督和贡献了一个更大的项目,其中包含50,000多行使用React Native编写的代码(除了native代码),如今正在生产环境中部署并运行顺利。我已经积累了足够的经验来找出React(和React Native)的亮点,以及它不在哪里 - 以及如何扩展它。android

注意:我知道大家中的一些人在阅读这篇文章时会指向Flutter。因为它的成熟度远不及它的竞争对手,我尚未考虑它。git

在撰写本文时,React Native的当前稳定版本为0.57,即将有0.58RC。

如下是个人想法:github

React Native最广为人知也是最不重要的的功能

React Native最广为人知的功能是它是跨平台的,但这并非它引发我注意的缘由。 React Native最重要的特性是它使用React,这样它支持一个通用的声明性布局。跨平台支持排在第二位。做为一名iOS开发人员,我一直在努力设计用户界面的方式不那么直观;自动布局系统。数据库

若是您的系统具备高度动态性,而且屏幕上的元素相互依赖(如抽屉和动画),那么Apple的Autolayout是管理屏幕上内容的最佳方式。可是,对于大多数Android和iOS应用程序,状况并不是如此。大多数Android和iOS应用程序都使用咱们习惯看到的标准元素:文本,按钮,列表,通用视图和图像以最相似于Web的方式布局。编程

在AutoLayout发明之间的时间里,FlexBox系统被发明并用做将事物放在屏幕上的事实标准。除了标准的Web使用以外,还有一些布局系统旨在利用FlexBox原则进行原生开发:react-native

有更多的接口库 - 这些只是众所周知的一些。他们有一个共同点,就是他们都使用声明式用户界面方法。bash

声明性用户界面的状况:

建立移动开发的声明性用户界面是为了解决传统布局系统所具备的问题。您声明了您的意图,系统会根据它们生成结果。架构

声明性用户界面解决的移动开发挑战不多以下:函数

组件化。 iOS在ViewControllers中使用ViewControllers并在视图中查看。 Android使用Fragments。二者都具备XML接口声明,而且都容许运行时视图实例化和编辑。当涉及将它们分解为较小的或重用它们时,你就是在进行一个小型的重构。在声明性用户界面中,默认状况下已经具备此功能。

开发者生产力。声明性用户界面负责为您调整组件大小。看看这段代码(React Native示例):

class TestTextLabel extends React.Component {
  render() {
    return (
      <view>
        <text>This is a small text</text>
        <text>{this}</text>
      </view>
    );
  }
}
复制代码

上面的代码渲染了一个只包含两个文本组件的Component。注意this.props.sampleText。若是此变量太长(例如 - 10000个字符长)会发生什么?结果将是组件将调整大小以适合整个文本。若是文本到达容许空间的末尾(屏幕,让咱们说),那么视图将被剪切,用户将没法看到整个文本。你须要一个滚动视图。

class TestTextLabel extends React.Component {
  render() {
    return (
      <ScrollView style={{flex : 1}}>
        <Text>This is a small text</Text>
        <Text>{this}</Text>
      </ScrollView>
    );
  }
}
复制代码

惟一改变的是添加<ScrollView>元素。若是是在iOS上,这须要进行更多工做。

协做 - Git Friendliness。我见过的每一个声明性UI都更好。

在iOS和Android上,若是你有大块UI,那你就作错了。可是,大型XML文件在大多数状况下是不可避免的(对于iOS来讲:XIB其实是XML文件)。它们的变化对代码审查者(或您)来讲没有任何意义 - 若是您不一样意之前哪一个版本(您或者其余开发人员的更改)保持完整,则拉动请求几乎是不可能的。

使用React和其余声明性UI库,这些问题在很大程度上被最小化,由于布局是实际代码 - 您能够更新,删除,合并,差别以及执行您一般对软件的任何其余部分执行的全部操做的代码。

关键是要了解“性能”到底是什么

您可能须要成为移动开发人员才能掌握性能概念并管理有效的内存和处理器使用。

Web开发人员能够在不了解Native的状况下使用React Native的概念仅适用于小型项目。一旦应用程序开始增加而且Redux商店的计算开始对应用程序的性能形成影响,您将须要了解Native端如何工做以了解为何会发生这种状况。您还须要意识到React Native中的Redux Store致使的从新渲染与DOM中发生的从新渲染并不彻底相同。这尤为适用于来自应用的Native端的组件。

同时,在React Native上从新渲染应用程序的组件会变得昂贵。因为React Native使用桥接器,所以您在render()函数内提供的任何指令都将从JavascriptCore传递到Java / Objective C ++。native端将采用JSX标记中给出的render()指令,并将它们转换为其native对应项,如视图,标签和图像。若是每秒进行数百次,那种翻译须要不可忽略的cpu时间。

在性能部门,彷佛React Native是更好的跨平台解决方案之一。可是,在某些关键领域仍然存在React Native的性能问题。

一个这样的例子是大型数据集(和列表)。在大型列表和网格视图的状况下,Android和iOS提供了一个出色且极其灵活的解决方案 - 回收视图。想象一下,当使用大型列表视图(iOS / Android)时,只渲染在任何给定时间显示的单元格。其余单元格被标记为可重复使用,以便在即将显示新单元格时能够重复使用它们。更改数据集时,操做系统只需更新显示的单元格。

React Native为大型数据集提供VirtualizedList及其派生(FlatList和SectionList)。然而,即便这样也有不少不足之处。存在性能开销,尤为是在SectionList中渲染复杂组件并尝试更新100多个对象的大型数据集时。更新机制使低端或中端移动设备运行缓慢。

为了解决这个问题,我已经从Redux切换到MobX,它为个人组件提供了更可预测的更新。此外,在大型列表的状况下,MobX能够更新特定单元而无需从新呈现整个列表。一般这也能够经过Redux实现,可是您须要覆盖componentShouldUpdate()并编写更多样板文件以免没必要要的从新渲染。在将其他变量复制到新状态时,您的reducer仍会执行一些没必要要的工做。

底线:当心。您使用React Native的事实意味着从您的应用程序实现最佳性能须要熟悉React的最佳实践和Native实践。

了解JS运行时及其对您的影响很是重要。

能够经过将调试信息发送到Chrome的网桥在React Native中进行调试。这意味着在设备中运行实际代码的过程与您调试代码的过程不一样。

Android和iOS上的React Native使用JavascriptCore执行Javascript。可是,调试工具在V8(Chrome)上运行。为了使系统更加分散,在撰写本文时,React Native在iOS上使用Apple的Javascript Core,而在Android上,他们使用的是3年前JS Core的构建脚本(由于Android没有提供任何JS运行时)像iOS这样的盒子Facebook必须本身构建)。这致使缺少JS功能,如Android上的代理对象支持和64位支持。所以,若是你想使用MobX 5+他/她是运气很差,除非你使用升级的Javascript运行时(继续阅读以了解如何作到这一点)。

运行时差别一般会致使错误只能在生产中重现。更糟糕的是,有些事情会变得难以辨认。

例如,当涉及React Native时,移动数据库的最佳解决方案是Realm。可是,当进入调试模式时,会发生这种状况:https://github.com/realm/realm-js/issues/491。 Realm的人已经解释了为何会这样 - 但最重要的是,若是咱们想要一个更稳定的调试解决方案,必须改进React Native的调试架构。好消息是我一直在使用Haul做为个人捆绑包,它容许我直接从个人iOS设备进行调试,而无需经过Chrome Dev Tools(不幸的是,你须要Mac,iOS模拟器和Safari)。

请注意,Facebook上的人已经知道这个问题,他们正在从新设计React Native的核心,以便Native和React Native部分能够共享相同的内存。完成此操做后,可能能够直接在设备的JavaScript运行时上进行调试。 React Native Fabric(UI-Layer Re-architecture)

不只如此,React Native社区如今提供了js android构建脚本,容许构建更新版本的JavascriptCore并将其嵌入到React Native应用程序中。这使Android的React Native Javascript功能与iOS相提并论,也为在Android上运行的React Native增长了64位支持铺平了道路。

使用React Native进行应用内导航很是棒

您是否开发过带身份验证的移动应用程序?若是用户收到推送通知而且必须首先经过登陆屏幕,而且只有在登陆后他才能看到推送通知内容屏幕,会发生什么?或者,若是您当前深深嵌套在应用程序中并但愿跳转到另外一个应用程序部分中的彻底不一样的区域做为对用户操做的响应,该怎么办?

像Native这样的问题能够经过一些努力在Native中解决。使用React Navigation,它们甚至都不是问题。与相关路线和导航跳跃的深度连接感受天然和流畅。还有其余导航库,但React Navigation被认为是事实上的标准。你应该试一试。这是React Native比iOS和Android更好的方式。

React Native is not a silver bullet

与任何其余技术同样,您须要在投资以前了解它是什么以及它是什么。如下

  • 是关于RN擅长什么的非详尽列表:
  • 内容驱动的应用程序
  • 具备相似Web的UI的应用程序。
  • 跨平台应用程序可能须要或可能不须要快速上市时间。

这里还有一份非详尽的清单描述RN还差的很远的地方:

  • 具备巨大列表的应用程序
  • 媒体驱动的应用程序无需布局(例如:简单/小型游戏,动画,视频处理)或屏幕到屏幕的过渡。
  • CPU密集型任务。

确实,对于React没法作到的事情,您能够在Native中编写所需的全部内容,而后从React Native调用相应的代码。但这意味着您须要为每一个平台(iOS,Android)编写一次代码,而后为Javascript接口编写额外的代码。

React Native的内部组件目前正在经历一个主要的重构,所以RN能够并行地同步执行更多操做,以便它能够与Native共享公共代码。 facebook.github.io/react-nativ… - 在此以前,您应该在决定是否使用它以前进行一些研究。

结论

React Native是一个通过深思熟虑且发展良好的平台。它为您的应用打开了NodeJS的世界,并让您在其中一个最好的布局系统中进行编程。它还为您提供了与Native方面的良好桥梁,以便您能够充分利用这两个世界。

然而,它也属于另外一个奇怪的类别 - 你须要一个或三个团队开发你的应用程序!在某些时候,您须要一些iOS和Android开发人员来构建React Native默认状况下没有的组件。一旦您的团队开始成长,您将不得不决定是否将您的应用程序设为100%Native。所以,不管您为下一个项目选择React Native,都会成为您须要拥有多少Native代码(Java / Kotlin / Swift / ObjC)的问题。

我我的的建议:若是你意识到你须要3个团队来开发一个应用程序的三个方面(一个iOS团队,一个Android团队和一个React团队)那么你应该能够一直使用原生iOS和Android并跳过React Native 。经过仅维护两个代码库而不是开发三个代码库,您将节省时间和金钱。

可是,若是你有一个由熟练的开发人员组成的小团队,而且想要构建一个内容应用程序或相似的东西,那么React Native是一个很好的选择。

相关文章
相关标签/搜索