📱 React Native 与移动跨端

一句话定性

移动跨端是前端的第一次远征。前端盯着 iOS/Android 这两块原生疆域,只有一个执念:别让我用两种语言、两支团队、写两遍同一个 App。 从 WebView 套壳到 React Native 的”JS 写原生组件”,这部历史就是不断在”复用 Web 技能”和”接近原生体验”之间寻找停火线——而 Flutter 干脆掀了桌子,告诉所有人:也许根本不该复用 Web。


一、它是什么 & 出现的时代

智能手机普及后,前端面对一个尴尬现实:用户的注意力从浏览器迁移到了原生 App,而原生 App 要用 Objective-C/Swift(iOS)和 Java/Kotlin(Android)分别写两遍。 对一支只会 HTML/CSS/JS 的前端团队来说,这是两座必须翻越的高山。

于是移动跨端按时间分成三代:

代际代表年代渲染方式一句话
第一代:WebView 套壳Cordova / PhoneGap / Ionic2009 起整个 App 是一个全屏 WebView”把网页装进 App 壳里”
第二代:JS 驱动原生React Native2015JS 逻辑 + 真正的原生组件”JS 写,但渲染交给原生”
(参照系)自绘引擎Flutter(非 JS,Dart)2017自带 Skia 引擎,每个像素自己画”谁的组件都不用,我自己画”

这是 跨端与全栈演进史 横向扩张主线的第一站

移动端是前端”领土扩张”踏出浏览器的第一步。它定下的张力——复用 vs. 原生——会在后面的桌面端、小程序里一再重演。


二、为什么会出现(解决上一代什么痛点)

原生双端开发的"两遍地狱"

  1. 一个功能写两遍:iOS 一套、Android 一套,语言不通、API 不同、UI 范式各异。开发与维护成本几乎翻倍。
  2. 前端团队的技能被锁在门外:公司养了一支会 React/Vue 的成熟前端团队,却完全无法参与 App 开发,人力错配。
  3. 发版慢:原生 App 要过应用商店审核,改一个文案都要重新提审,迭代节奏远慢于 Web 的”刷新即更新”。

第一代(Cordova/PhoneGap,2009)的回答最简单粗暴:既然 App 能装一个 WebView,那我把整个网页塞进去不就行了? 一套 HTML/CSS/JS,通过 Cordova 提供的 JS bridge 调用摄像头、GPS 等原生能力。Ionic 在此基础上提供了一套”看起来像原生”的 UI 组件库。

这解决了”复用 Web 技能”的诉求,但很快撞上天花板。


三、核心机制 & 为什么流行

第一代的崩塌,催生 React Native

WebView 套壳的致命伤是:它本质上还是一个网页,所有交互都隔着 WebView 这层玻璃。 滚动卡顿、动画掉帧、列表长了就崩——用户一眼就能看出”这不是原生 App”。“uncanny valley(恐怖谷)“式的体验,让 Cordova 系沦为对体验不敏感的内部工具/简单应用的选择。

2015 年,Facebook 开源 React Native,提出了一个关键升级:

React Native 的核心洞察:"Learn once, write anywhere"

别再用 WebView 渲染了。JS 只负责描述 UI(用 React 的组件心智),但真正渲染出来的,是平台的原生组件——<View> 在 iOS 上变成 UIView,在 Android 上变成 android.view

// 这不是 HTML,<View>/<Text> 会被映射成真正的原生组件
function Card() {
  return (
    <View style={styles.card}>
      <Text>Hello Native</Text>
    </View>
  );
}

注意它的口号不是 React 的 “write once, run anywhere”,而是 “learn once, write anywhere”——承认两端有差异,但心智和技能可以复用。这是对”复用 vs. 原生”光谱的一次精妙折中。

架构:JS 线程 + 原生线程 + Bridge。 JS 在独立线程跑业务逻辑,通过一座异步的 Bridge(后来演进为 JSI/Fabric 的同步调用)与原生线程通信,原生线程负责真正的渲染和手势。逻辑用 JS 写(可复用前端技能),渲染用原生(保证体验)。

为什么流行

  • 技能复用兑现了:会 React 的人几乎能直接写 RN,组件、props、state、Hooks 全部沿用。前端团队第一次真正能做 App。
  • Facebook/Instagram 背书 + 热更新(CodePush) 绕开了应用商店审核的痛点。
  • 生态借力 npm:海量 JS 库可复用。

Flutter:另一条路(重要参照系)

2017 年 Google 推出 Flutter(用 Dart 语言,不属于 JS 系)。它的选择是光谱的另一个极端:既不套 WebView,也不用原生组件,而是自带 Skia 渲染引擎,每个像素都自己画。 好处是两端像素级一致、性能接近原生;代价是完全不复用 Web 技能(要学 Dart),且无法直接用原生组件。

为什么要把 Flutter 放进这部 JS 主导的历史?

因为 Flutter 是对整条母题的反命题。当前端的扩张逻辑是”用 JS 复用 Web 技能征服一切”时,Flutter 站出来说:“复用 Web 技能”本身可能就是错的约束——如果体验才是第一目标,那就别复用,从渲染层重做。 这是第一性原理对”从众假设”的一次正面挑战。RN 和 Flutter 之争,本质是”技能复用优先” vs. “体验一致优先”两种价值观之争。


四、带来的新问题 / 副作用

"JS 写原生"的抽象泄漏

  1. Bridge 性能瓶颈(早期):JS 与原生通过异步 Bridge 序列化通信,高频场景(复杂动画、大列表快速滚动)会卡顿。这逼出了 RN 后来的 JSI / Fabric / TurboModules 重构(把异步 Bridge 换成同步直调)。
  2. 原生模块维护的隐性成本:一旦要用 RN 没封装的能力(蓝牙、特定 SDK),还是得写原生代码 + 桥接层。号称”不用碰原生”,最后往往还是要懂 iOS/Android。 抽象泄漏了。
  3. 版本碎片与升级地狱:RN 版本、各原生依赖、Gradle/CocoaPods、第三方库的兼容矩阵极其脆弱,“升级 RN 大版本”在团队里是出了名的苦差事。
  4. “差不多但不完全一样”:两端总有细微差异要单独处理,理想的”一套代码”在边角处不断渗水。

第一性原理的拷问:跨端省下的”写两遍”的钱,有多少被”调两端差异 + 维护原生桥接 + 追 RN 版本”重新花掉了? 这是每个团队选型时必须自问的账。


五、为什么会衰落 / 现状

React Native 没有衰落,而是进入了成熟期并完成了关键自我进化:

RN 的自我革命

  • 架构重写(JSI/Fabric/TurboModules):用同步的 JSI 取代异步 Bridge,根治了第一代架构的性能瓶颈。
  • Expo 成为事实标准入口:Expo 极大降低了 RN 的环境配置与原生集成门槛,让”建一个 RN App”像建一个网页一样轻。
  • 与全栈合流:Expo Router 引入了类似 Next.js 的文件路由,RN 正在被纳入”一套元框架通吃 Web + 移动”的版图(详见 跨端与全栈演进史)。

现状格局:

  • React Native:JS 生态、可复用前端团队的首选,大量大厂 App 在用。
  • Flutter:对 UI 一致性和性能要求极高、团队愿意学 Dart 的场景里强势。
  • Cordova/Ionic:基本退居简单应用 / 企业内部应用,被 RN 和 Flutter 两面挤压。

六、对后续技术的影响(因果链)

原生双端开发"写两遍"的痛点
        │
        ↓
第一代:Cordova/PhoneGap(2009)── 整个 App 套一个 WebView
        │  └─ Ionic:在套壳上加"类原生"UI 组件库
        │
        ├─► 致命伤:隔着 WebView,体验掉进恐怖谷
        │
        ↓
React Native(2015):JS 写逻辑 + 原生组件渲染 + Bridge
        │  口号从 "write once" 降级为 "learn once"(承认差异)
        │
        ├─► Bridge 性能瓶颈 ──► JSI/Fabric/TurboModules 重构
        ├─► 配置复杂 ──► Expo 成为标准入口
        ├─► 文件路由 ──► Expo Router ──► 并入全栈元框架版图 [[跨端与全栈演进史]]
        │
        ‖ (反命题)
        ↓
Flutter(2017,Dart 非 JS):自绘引擎,不复用 Web,但体验一致
        │  挑战了"复用 Web 技能"这个前提本身
        ↓
移动跨端定型:RN(技能复用派) vs Flutter(体验一致派)长期共存

历史地位

React Native 是前端”领土扩张”的第一面旗帜,它证明了前端的组件心智可以脱离浏览器、驱动原生 UI。它定下的”复用 vs. 原生”光谱,成为之后整部跨端史的坐标系。而 Flutter 的存在则永远提醒着:“用一套 JS 技能统一一切”是一种选择,不是一条物理定律。


🔗 同组:跨端与全栈演进史 | 小程序生态 | Electron与桌面端 | 全栈框架与BFF | RSC与前后端边界模糊 🔗 框架:React | Vue | 前端框架演进史 🔗 时代:2013-2018 SPA时代 | 2018-2023 工程化时代 🔗 运行时:Node.js | 语言:TypeScript