Expo 讲座:Adam 谈导航解构
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
Adam Miskiewicz 来自 Expo,在上周的 Expo 办公时间中探讨了移动导航以及 React Native 库 ex-navigation。
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
Adam Miskiewicz 来自 Expo,在上周的 Expo 办公时间中探讨了移动导航以及 React Native 库 ex-navigation。
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
将应用发布到应用商店后,国际化是扩大受众范围的下一步。全球有超过 20 个国家和众多人口使用从右到左(RTL)的语言。因此,为这些用户提供 RTL 支持是必要的。
我们很高兴地宣布,React Native 已经改进以支持 RTL 布局。该功能现在已在 react-native 的主分支中提供,并将在下一个候选版本(RC)中发布:v0.33.0-rc。
这涉及到更改 RN 使用的核心布局引擎 css-layout、RN 核心实现,以及特定的开源 JS 组件以支持 RTL。
为了在生产环境中测试 RTL 支持,最新版本的 Facebook Ads Manager 应用(首个跨平台 100% RN 应用)现已提供阿拉伯语和希伯来语的 RTL 布局,支持 iOS 和 Android。以下是这些 RTL 语言下的效果:

css-layout 的布局中已有 start 和 end 的概念。在从左到右(LTR)布局中,start 表示 left,end 表示 right。但在 RTL 中,start 表示 right,end 表示 left。这意味着我们可以让 RN 依赖 start 和 end 的计算来确定正确的布局,包括 position、padding 和 margin。
此外,css-layout 已经让每个组件的方向继承自其父组件。这意味着,我们只需将根组件的方向设置为 RTL,整个应用就会翻转。
下图从高层次描述了这些更改:

这些更改包括:
在 RN 核心实现中,将 left 和 right 映射为 start 和 end(针对影子节点)
并公开了一个桥接实用模块来帮助控制 RTL 布局
通过此更新,当您为应用启用 RTL 布局时:
每个组件的布局将水平翻转
如果您使用的是支持 RTL 的开源组件,一些手势和动画将自动具有 RTL 布局
只需极少的额外工作,即可让您的应用完全支持 RTL
要支持 RTL,首先需要将 RTL 语言包添加到应用中。
在你的应用原生代码起始处调用 allowRTL() 函数以启用 RTL 布局。我们提供此工具函数,确保仅在你的应用准备就绪时才应用 RTL 布局。示例如下:
iOS:
// in AppDelegate.m
[[RCTI18nUtil sharedInstance] allowRTL:YES];
Android:
// in MainActivity.java
I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
sharedI18nUtilInstance.allowRTL(context, true);
对于 Android 应用,你需要在 AndroidManifest.xml 文件的 <application> 元素中添加 android:supportsRtl="true" 属性。
现在,当你重新编译应用并将设备语言切换为 RTL 语言(如阿拉伯语或希伯来语)时,应用布局应会自动切换为 RTL 模式。
通常情况下,大多数组件已原生支持 RTL 布局,例如:
但需要注意几种特殊情况,这时你需要使用 I18nManager。在 I18nManager 中,常量 isRTL 可判断当前布局是否为 RTL,从而进行相应调整。
当组件包含图标或图像时,它们在 LTR 和 RTL 布局中的显示方向不会自动改变。因此你需要根据布局手动调整方向:
以下两种方法可实现图标方向切换:
为图像组件添加 transform 样式:
<Image
source={...}
style={{transform: [{scaleX: I18nManager.isRTL ? -1 : 1}]}}
/>
或根据布局方向切换图像源:
let imageSource = require('./back.png');
if (I18nManager.isRTL) {
imageSource = require('./forward.png');
}
return <Image source={imageSource} />;
在 Android 和 iOS 开发中,切换到 RTL 布局时手势和动画方向与 LTR 相反。目前在 React Native 中,手势和动画的支持不在核心代码层,而是在组件层。好消息是部分组件(如 SwipeableRow 和 NavigationExperimental)已支持 RTL 布局。但其他涉及手势的组件仍需手动适配。
SwipeableRow 是演示 RTL 手势支持的典型范例。


// SwipeableRow.js
_isSwipingExcessivelyRightFromClosedPosition(gestureState: Object): boolean {
// ...
const gestureStateDx = IS_RTL ? -gestureState.dx : gestureState.dx;
return (
this._isSwipingRightFromClosed(gestureState) &&
gestureStateDx > RIGHT_SWIPE_THRESHOLD
);
},
// SwipeableRow.js
_animateBounceBack(duration: number): void {
// ...
const swipeBounceBackDistance = IS_RTL ?
-RIGHT_SWIPE_BOUNCE_BACK_DISTANCE :
RIGHT_SWIPE_BOUNCE_BACK_DISTANCE;
this._animateTo(
-swipeBounceBackDistance,
duration,
this._animateToClosedPositionDuringBounce,
);
},
即使在初始发布 RTL 兼容应用后,您仍可能需要迭代新功能。为提高开发效率,I18nManager 提供了 forceRTL() 函数,无需更改测试设备语言即可快速进行 RTL 测试。您可以在应用中添加简单的切换开关实现此功能。以下是 RNTester 中 RTL 示例的参考实现:

<RNTesterBlock title={'Quickly Test RTL Layout'}>
<View style={styles.flexDirectionRow}>
<Text style={styles.switchRowTextView}>forceRTL</Text>
<View style={styles.switchRowSwitchView}>
<Switch
onValueChange={this._onDirectionChange}
style={styles.rightAlignStyle}
value={this.state.isRTL}
/>
</View>
</View>
</RNTesterBlock>;
_onDirectionChange = () => {
I18nManager.forceRTL(!this.state.isRTL);
this.setState({isRTL: !this.state.isRTL});
Alert.alert(
'Reload this page',
'Please reload this page to change the UI direction! ' +
'All examples in this app will be affected. ' +
'Check them out to see what they look like in RTL layout.',
);
};
开发新功能时,您可以轻松切换此按钮并重新加载应用查看 RTL 布局。这样做的好处是无需更改语言设置即可测试,但如下一节所述,某些文本对齐方式不会自动改变。因此建议在正式发布前使用 RTL 语言全面测试应用。
RTL 支持已覆盖应用中的大部分用户体验,但目前仍存在以下限制:
不存在"绝对左/右"定位
如前所述,我们将 JS 端的 left/right 样式映射为 start/end,导致 RTL 布局中代码的 left 实际显示为"右",right 显示为"左"。这减少了代码修改量,但也意味着无法在代码中指定"绝对左侧"或"绝对右侧"。未来可能需要支持组件独立控制布局方向。
提升手势和动画的 RTL 开发体验
当前实现手势和动画的 RTL 兼容性仍需较多编程工作。未来将探索更友好的开发方案。
查看 RNTester 中的 RTLExample 深入了解 RTL 支持,欢迎反馈使用体验!
最后,感谢您的阅读!希望 React Native 的 RTL 支持能帮助您拓展国际用户群体!
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
上周我有幸参加了在 Zynga 旧金山办公室举办的 React Native 见面会。现场约有 200 人参加,这是一个绝佳的机会,让我结识了附近同样对 React Native 感兴趣的其他开发者。

我特别想了解 Zynga、Netflix 和 Airbnb 等公司如何使用 React 和 React Native。当晚的议程安排如下:
React 中的快速原型设计
为 React Native 设计 API
弥合鸿沟:在现有代码库中使用 React Native
不过活动开始前,我们先进行了简短介绍和近期动态回顾:
你知道吗?React Native 已是 GitHub 上最热门的 Java 仓库
rnpm 现已并入 React Native 核心!现在你可以使用 react-native link 替代 rnpm link 来安装带原生依赖的库
React Native 见面会社区正在快速壮大!目前全球各地的聚会小组已有超过 4,800 名开发者参与
如果这些聚会在你附近举办,我强烈建议参加!
新闻分享环节后,当晚的东道主 Zynga 进行了简短介绍。Abhishek Chadha 分享了他们如何利用 React 在移动端快速原型设计新体验,并演示了一款类 Draw Something 应用的快速原型。他们采用与 React Native 类似的方法,通过桥接机制访问原生 API。当 Abhishek 调用设备摄像头拍摄观众照片并在某人头上绘制帽子时,这一点得到了生动展示。
接下来是当晚的首场主题演讲。Netflix 高级软件工程师 Clarence Leung 分享了为 React Native 设计 API 的经验。他首先指出开发者可能构建的两类库:标签栏/日期选择器等组件库,以及相机相册/应用内支付等原生服务访问库。在构建 React Native 库时,主要有两种实现路径:
提供平台特定组件
构建跨平台库(Android/iOS 保持相似 API)
每种方案各有考量,具体选择取决于你的实际需求。
方案一
Clarence 以 React Native 核心的 DatePickerIOS 和 DatePickerAndroid 为例说明平台特定组件。iOS 的日期选择器作为 UI 元素直接嵌入视图,而 Android 则以模态框形式呈现。这种情况下提供独立组件是合理的设计选择。
方案二
另一方面,照片选择器在 Android 和 iOS 上的处理方式类似。存在一些细微差异——例如 Android 不会像 iOS 那样将照片分组到"自拍"等文件夹中——但这些差异可以通过 if 语句和 Platform 组件轻松处理。
无论您选择哪种方法,最小化 API 表面并构建特定于应用的库都是明智之举。例如,iOS 的应用内购买框架支持一次性消耗性购买以及可续订订阅。如果您的应用仅需支持消耗性购买,您可以在跨平台库中直接省略订阅功能。

Clarence 演讲结束后进行了简短的问答环节。其中透露的一个有趣细节是:Netflix 为这些库编写的 React Native 代码中,约 80% 可在 Android 和 iOS 平台共享。
当晚的最后一场演讲来自 Airbnb 的 Leland Richardson,聚焦于在现有代码库中使用 React Native。我深知使用 React Native 从零开发新应用非常便捷,因此对 Airbnb 在现有原生应用中集成 React Native 的经验格外感兴趣。
Leland 首先介绍了 greenfield 应用与 brownfield 应用的区别。Greenfield 指无需考虑历史包袱的全新项目,而 brownfield 项目则需要兼顾现有工程需求、开发流程及多团队协作等复杂因素。
开发 greenfield 应用时,React Native CLI 会为 Android 和 iOS 创建统一仓库。Airbnb 面临的第一个挑战是:他们的 Android 和 iOS 应用分属独立仓库。采用多仓库结构的公司在引入 React Native 前需跨越这一障碍。
为此,Airbnb 首先为 React Native 代码建立了专属仓库。他们通过持续集成服务器将 Android/iOS 仓库镜像至此新仓库,测试运行并构建 bundle 后,再将产物同步回原仓库。这样移动工程师可在不改变开发环境的前提下处理原生代码——无需安装 npm、运行打包服务或手动构建 JavaScript bundle。而编写 React Native 的工程师则直接在专属仓库工作,无需操心跨平台代码同步。
该方案存在明显缺陷:无法实现原子更新。涉及原生和 JavaScript 联动的变更需拆分成三个独立 PR,且必须谨慎协调合并顺序。为避免冲突,若主分支在构建期间发生变化,CI 将中止向 Android/iOS 仓库的同步。这在高频提交时期(如版本发布阶段)会导致严重延迟。
Airbnb 现已转向单仓库方案。值得庆幸的是该方案已在规划中,当 Android/iOS 团队熟悉 React Native 工作流后,便欣然推动了单仓库迁移进程。
这基本解决了分仓库方案的问题。Leland 也指出单仓库会给版本控制系统带来更大压力,小型公司需评估此影响。

Leland 演讲的后半段聚焦于 React Native 的核心痛点:导航解决方案。他剖析了丰富的导航库生态(包括官方和第三方方案),特别提到 NavigationExperimental 看似前景广阔,最终却未能满足其实际需求。
实际上,现有的导航库似乎都无法很好地支持遗留应用(brownfield app)。这类应用要求导航状态完全由原生应用掌控。例如,当用户会话在 React Native 视图展示期间过期时,原生应用应能随时接管并弹出登录界面。
Airbnb 还希望避免在过渡期间用 JavaScript 实现的导航栏替换原生导航栏,因为这种切换可能产生割裂感。最初他们仅限模态视图使用 React Native,但这显然限制了 React Native 在整个应用中的推广范围。
因此他们决定开发专属库 airbnb-navigation。由于该库深度耦合 Airbnb 的代码库,目前尚未开源,但他们计划在今年年底前发布。
此处不深入解析库的 API 设计,但核心要点包括:
必须预先注册所有场景(scene)
每个场景都在独立的 RCTRootView 中渲染,并通过各平台原生方式呈现(例如 iOS 使用 UINavigationController)
场景中的主 ScrollView 需包裹在 ScrollScene 组件内,从而支持点击状态栏自动回滚等原生行为
场景转场由原生系统处理,无需担心性能损耗
自动支持 Android 返回键操作
通过无界面的 Navigator.Config 组件实现基于视图控制器的导航栏样式配置
同时也需注意以下限制:
导航栏作为原生组件难以通过 JavaScript 深度定制(这是该库的硬性要求)
通过桥接传递的 ScreenProps 需序列化/反序列化,传递大量数据时需谨慎
导航状态由原生应用管控(核心设计原则),因此 Redux 等方案无法操作导航状态
演讲后的问答环节中,Airbnb 表示对 React Native 整体满意。他们计划采用 Code Push 实现热修复以绕过应用商店审核,工程师们尤其推崇 Live Reload 功能——无需重新编译原生应用即可实时查看代码改动。
活动结束时分享了更多 React Native 动态:
Deco 宣布推出 React Native 应用展示墙,邀请参会者提交作品
会议特别提及近期完成的文档全面升级
Deco IDE 联合创始人 Devin Abbott 将开设 React Native 入门课程

技术沙龙是向社区开发者学习交流的绝佳机会。期待未来参与更多 React Native 线下聚会。若您也参加相关活动,欢迎随时交流探讨如何让 React Native 更好地服务您的开发需求!
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
卓越的开发者体验离不开卓越的文档支持。编写优质文档需要付出诸多努力——理想的文档应具备简洁性、实用性、准确性、完整性和愉悦性。近期我们根据您的反馈持续优化文档,现与您分享部分改进成果。
当您学习新库、新编程语言或新框架时,总会有个美妙瞬间:初次编写代码片段,尝试运行,观察结果...然后它_真的_运行成功了!您亲手创造了实际成果。我们致力于将这种沉浸式体验融入文档中,例如:
import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';
class ScratchPad extends Component {
render() {
return (
<View style={{flex: 1}}>
<Text style={{fontSize: 30, flex: 1, textAlign: 'center'}}>
Isn't this cool?
</Text>
<Text style={{fontSize: 100, flex: 1, textAlign: 'center'}}>
👍
</Text>
</View>
);
}
}
AppRegistry.registerComponent('ScratchPad', () => ScratchPad);
我们相信这些内联示例(借助 Devin Abbott 开发的 react-native-web-player 模块)是学习 React Native 基础的最佳途径。为此我们更新了面向新手的 React Native 教程,尽可能采用此类示例。欢迎体验——如果您曾好奇修改示例代码会产生什么变化,这将是绝佳的探索方式。此外,若您正在开发工具并希望在自有站点展示实时 React Native 示例,react-native-web-player 能让此过程变得简单直接。
核心模拟引擎由 Nicolas Gallagher 的 react-native-web 项目提供,该项目支持在 Web 端展示 Text 和 View 等 React Native 组件。如果您希望构建共享大量代码的移动端与 Web 端应用,请关注 react-native-web。
React Native 某些功能存在多种实现方式,我们收到反馈建议需要更明确的指导。
全新推出的导航指南对比了不同方案(Navigator、NavigatorIOS、NavigationExperimental)并提供选用建议。中期规划中我们将改进并整合这些接口,短期目标则是通过优化指南减轻您的决策负担。
我们还新增了触摸事件处理指南,讲解创建类按钮界面的基础知识,并简要归纳了处理触摸事件的不同方式。
另一优化重点是 Flexbox 布局,包含使用 Flexbox 处理布局和控制组件尺寸的教程,以及虽不炫酷但极具实用价值的React Native 布局控制属性全集。
在本地搭建 React Native 开发环境时,您需要完成大量安装配置工作。虽然难以将安装过程变得趣味十足,但我们至少能使其尽可能快速无痛。
我们构建了新版入门流程,支持预先选择开发操作系统与移动操作系统,将所有设置说明整合至统一界面。我们完整走查安装流程以确保各环节可靠运行,并为每个决策点提供明确建议。经过同事实测验证,我们确信这是项显著改进。
我们还在将 React Native 集成到现有应用的指南上做了改进。许多使用 React Native 的大型应用(包括 Facebook 应用自身)实际上都是部分采用 React Native 构建,部分使用常规开发工具完成的。我们希望这份指南能让更多人轻松采用这种开发模式。
您的反馈决定了我们的工作优先级。我知道有人读完这篇博文会想:"文档改进?切!X 功能的文档还是那么烂!"——这种态度很棒,我们需要这种能量。根据反馈类型的不同,最佳提交方式也有所区别:
如果发现文档中的具体错误(如描述不准确或代码无法运行),请提交 issue。务必添加"Documentation"标签,方便我们快速分配给对应负责人。
如果没有具体错误,但某些文档内容存在根本性困惑,则不适合提交 GitHub issue。请到 Canny 平台说明需要改进的文档区域。这能帮助我们在编写指南等系统性工作时合理规划优先级。
感谢您阅读至此,也感谢您使用 React Native!
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
自我们将 React Native 开源以来,已经过去了一年。当初只是几位工程师的构想,如今已成为 Facebook 内外产品团队广泛使用的框架。今天在 F8 大会上,我们宣布微软正将 React Native 引入 Windows 生态,让开发者能够在 Windows PC、Phone 和 Xbox 上构建 React Native 应用。微软还将提供 Visual Studio Code 的 React Native 扩展和 CodePush 等开源工具与服务,帮助开发者在 Windows 平台上创建 React Native 应用。此外,三星正在为其混合平台构建 React Native,使开发者能够为数百万台 SmartTV 及移动和可穿戴设备开发应用。我们还发布了 Facebook SDK for React Native,让开发者能更轻松地将登录、分享、应用分析和 Graph API 等 Facebook 社交功能集成到应用中。短短一年间,React Native 已经改变了开发者在各大主流平台的构建方式。
这是一段激动人心的旅程——而我们才刚刚启航。在此,我们将回顾 React Native 自一年前开源以来的成长与演变,分享我们途中遇到的挑战,并展望未来的发展方向。
本文为节选。阅读完整文章请访问 Facebook Code。
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
React Native 让您能够使用 JavaScript 构建 Android 和 iOS 应用,借助 React 和 Relay 的声明式编程模型。这种模式带来了更简洁易懂的代码、无需编译周期的快速迭代能力,以及跨平台代码的轻松复用。您可以更快地交付产品,专注于真正重要的细节,让应用呈现出令人惊艳的视觉效果和交互体验。性能优化正是其中关键一环。本文将讲述我们如何使 React Native 应用启动速度提升两倍的故事。
更快的应用意味着内容加载更迅速,用户有更多时间进行交互;流畅的动画则能带来愉悦的使用体验。在新兴市场,2011 年款手机搭配2G 网络仍是主流,此时性能优化往往决定着应用能否真正投入使用。
自从在iOS和Android平台发布 React Native 以来,我们持续优化了列表滚动性能、内存效率、UI 响应速度以及应用启动时间。启动速度决定了用户对应用的第一印象,同时考验着框架的各个组成部分,因此这是最具挑战性也最值得投入的优化方向。
本文为节选,完整内容请阅读 Facebook Code 博客。
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
React Native 的核心目标是提供最佳的开发者体验。其中关键环节是从保存文件到看到变更所需的时间。我们的目标是将这个反馈循环压缩到 1 秒以内,即使应用规模持续增长。
我们通过三大特性逼近这个理想目标:
采用 JavaScript 语言,避免冗长的编译周期
实现名为 Packager 的工具,将 ES6/Flow/JSX 文件转换为虚拟机可理解的常规 JavaScript。该工具设计为服务架构,在内存中保存中间状态以实现快速增量更新,并充分利用多核性能
构建 Live Reload 功能,实现保存时自动重载应用
至此,开发者的瓶颈不再是重载应用所需时间,而是应用状态的丢失。典型场景是:当你在距离启动屏多个页面之外的模块上工作时,每次重载都必须重复点击相同路径才能返回工作区,导致开发循环延长至数秒
热重载的核心原理是保持应用运行状态,在运行时注入已编辑文件的新版本。这样就不会丢失任何状态,特别适合调整 UI 元素
百闻不如一见,请对比 Live Reload(现有)与 Hot Reload(全新)的实际效果:
仔细观察会发现:系统能从红屏错误中自动恢复,还能直接导入新增模块而无需完全重载
重要提示: 由于 JavaScript 是强状态语言,热重载无法完美实现。实践中我们发现当前方案能覆盖大多数常规场景,若出现异常随时可通过完全重载恢复
热重载功能自 0.22 版本起可用,启用方式:
打开开发者菜单
点击"启用热重载"
了解其价值和使用方法后,现在进入精彩环节:运作原理揭秘
热重载基于 模块热替换(HMR)功能构建。该技术由 webpack 首创,我们在 React Native Packager 中实现了它。HMR 让 Packager 监听文件变更,并向应用内嵌的轻量 HMR 运行时发送更新
简言之,HMR 更新包含变更 JS 模块的新代码。运行时接收后会将旧模块代码替换为新版本:

HMR 更新的内容不仅包含目标模块代码,因为单纯替换代码不足以让运行时感知变更。问题在于模块系统可能已缓存目标模块的_导出值_。例如某个应用包含两个模块:
// log.js
function log(message) {
const time = require('./time');
console.log(`[${time()}] ${message}`);
}
module.exports = log;
// time.js
function time() {
return new Date().getTime();
}
module.exports = time;
log 模块负责输出带时间戳的消息,时间数据由 time 模块提供
应用打包时,React Native 通过 __d 函数在模块系统中注册各模块。对于此应用,在众多 __d 定义中会有针对 log 的注册:
__d('log', function() {
... // module's code
});
该调用将每个模块的代码包裹在一个匿名函数中,我们通常称之为工厂函数。模块系统运行时负责跟踪每个模块的工厂函数、是否已执行以及执行结果(导出值)。当模块被引入时,模块系统要么提供已缓存的导出值,要么首次执行该模块的工厂函数并保存结果。
假设您启动应用并引入 log 模块。此时 log 和 time 的工厂函数均未执行,因此没有导出值被缓存。接着用户修改 time 模块使其返回 MM/DD 格式的日期:
// time.js
function bar() {
const date = new Date();
return `${date.getMonth() + 1}/${date.getDate()}`;
}
module.exports = bar;
Packager 会将 time 的新代码发送至运行时(步骤1)。当 log 最终被引入时,其导出的函数会执行并使用 time 的修改(步骤2):

现在假设 log 的代码在顶层引入了 time:
const time = require('./time'); // top level require
// log.js
function log(message) {
console.log(`[${time()}] ${message}`);
}
module.exports = log;
当 log 被引入时,运行时将缓存其导出值及 time 的导出值(步骤1)。若此时修改了 time 模块,热更新流程不能仅替换完 time 的代码就结束。否则当 log 执行时,它仍会使用缓存的旧版 time 代码。
为了让 log 获取 time 的变更,我们需要清除其缓存的导出值(步骤3)。最后当 log 再次被引入时,其工厂函数将重新执行,此时会引入新版 time 代码。

React Native 的 HMR 通过引入 hot 对象扩展了模块系统。该 API 基于 webpack 的实现。hot 对象暴露的 accept 函数允许您定义回调,在模块需要热替换时执行。例如,若将 time 代码修改如下,每次保存时控制台将显示 "time changed":
// time.js
function time() {
... // new code
}
module.hot.accept(() => {
console.log('time changed');
});
module.exports = time;
请注意,仅在极少数情况下需要手动使用此 API。热重载功能在大多数常见场景中均可开箱即用。
如前所述,有时仅接受 HMR 更新并不足够——因为使用被热替换模块的其他模块可能已被执行且其导入值已缓存。例如,假设电影应用示例的依赖树中,顶层 MovieRouter 依赖于 MovieSearch 和 MovieScreen 视图,而这两个视图又依赖于前例中的 log 和 time 模块:

若用户访问了电影搜索视图但未访问其他视图,除 MovieScreen 外所有模块的导出值都会被缓存。当 time 模块变更时,运行时必须先清除 log 的导出值才能使其获取 time 的变更。流程不会就此结束:运行时会递归向上处理所有父模块直至被完全接受。因此它会找到依赖 log 的模块并尝试接受更新:对于未加载的 MovieScreen 可跳过;对于 MovieSearch 则需清除其导出值并递归处理父模块;最终同样处理 MovieRouter 并因无上级依赖而终止。
为遍历依赖树,运行时通过 HMR 更新从 Packager 获取反向依赖树。此例中运行时将收到如下 JSON 对象:
{
modules: [
{
name: 'time',
code: /* time's new code */
}
],
inverseDependencies: {
MovieRouter: [],
MovieScreen: ['MovieRouter'],
MovieSearch: ['MovieRouter'],
log: ['MovieScreen', 'MovieSearch'],
time: ['log'],
}
}
要让 React 组件实现热重载会稍显棘手。问题在于如果直接替换新旧代码,我们会丢失组件状态。针对 React Web 应用,Dan Abramov 开发了一套 Babel 转换器,利用 webpack 的 HMR API 解决了这个问题。简言之,他的方案通过在转换阶段为每个 React 组件创建代理来实现。这些代理组件负责保存状态,并将生命周期方法委托给实际组件(即热重载的目标组件):
除了创建代理组件,该转换器还定义了包含强制 React 重新渲染组件的 accept 函数。这样我们就能在不丢失应用状态的前提下热更新渲染代码。
React Native 自带的默认转换器使用 babel-preset-react-native,其配置方式与你在基于 webpack 的 React Web 项目中使用 react-transform 完全一致。
要为 Redux 启用热重载,操作方式与基于 webpack 的 Web 项目类似:
// configureStore.js
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import reducer from '../reducers';
export default function configureStore(initialState) {
const store = createStore(
reducer,
initialState,
applyMiddleware(thunk),
);
if (module.hot) {
module.hot.accept(() => {
const nextRootReducer = require('../reducers/index').default;
store.replaceReducer(nextRootReducer);
});
}
return store;
};
当你修改 reducer 时,接受该 reducer 的代码将被发送到客户端。客户端会识别到 reducer 无法自我更新,于是查找所有引用它的模块并尝试更新。最终流程会到达唯一的 store —— 即 configureStore 模块,它将接受 HMR 更新。
如果你有兴趣帮助改进热重载功能,推荐阅读 Dan Abramov 关于热重载未来的文章并参与贡献。例如 Johny Days 正在实现多客户端同步热重载。这项功能的维护与优化需要大家共同参与。
通过 React Native,我们得以重新思考应用构建方式以优化开发体验。热重载只是其中一环,还能通过哪些创新方案让体验更上一层楼?
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
随着近期 React 在 Web 端的发布和 React Native 在移动端的推出,我们为开发者提供了构建产品的新前端框架。打造健壮产品的关键要素是确保所有人都能使用它,包括视力障碍或其他残疾人士。React 和 React Native 的可访问性 API 能让你构建的应用体验适用于使用辅助技术的用户,例如为盲人和视障人士设计的屏幕阅读器。
本文将重点讨论 React Native 应用。我们将 React 可访问性 API 设计得与 Android 和 iOS 原生 API 的体验保持一致。如果你曾为 Android、iOS 或 Web 开发过无障碍应用,应该会对 React AX API 的框架和术语体系感到熟悉。例如,你可以让 UI 元素变得 accessible(从而暴露给辅助技术),并通过 accessibilityLabel 为元素提供文本描述:
<View accessible={true} accessibilityLabel=”This is simple view”>
让我们通过 Facebook 自家的一款 React 产品 广告管理应用,来深入探索 React AX API 的实际应用。
本文为节选内容,完整文章请阅读 Facebook Code。
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
今年早些时候,我们推出了 React Native for iOS。React Native 将开发者们在 Web 上熟悉的 React 特性——声明式自包含 UI 组件和快速开发周期——带到了移动平台,同时保留了原生应用的速度、保真度和体验。今天,我们很高兴发布 React Native for Android。
在 Facebook,我们在生产环境中使用 React Native 已经超过一年。差不多正好一年前,我们的团队着手开发 Ads Manager 应用。我们的目标是创建一个新应用,让数百万在 Facebook 上投放广告的用户能够随时随地管理账户并创建新广告。最终,它不仅是 Facebook 第一个完全使用 React Native 构建的应用,也是第一个跨平台应用。在本文中,我们将分享我们如何构建这个应用,React Native 如何让我们更快地推进,以及我们吸取的经验教训。
本文为节选。阅读完整文章请访问 Facebook Code。
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
两年前我们将 React 推向世界,此后它在 Facebook 内外都取得了令人瞩目的发展。如今,即使没有人被强制使用它,Facebook 的新 Web 项目通常都以某种形式采用 React 构建,整个行业也都在广泛接纳这项技术。工程师们每天选择使用 React,因为它能让他们更专注于产品本身,而非与框架作斗争。然而直到我们使用 React 开发一段时间后,才开始真正理解其强大之处。
React 要求我们将应用拆分为离散的组件,每个组件代表单一视图。这些组件让产品迭代更轻松——因为修改局部功能时无需在脑中构建整个系统。更重要的是,React 用声明式 API 封装了 DOM 的易变命令式接口,提升了抽象层级并简化了编程模型。我们发现使用 React 构建时,代码可预测性大幅提高。这种可预测性让我们能自信地快速迭代,应用也因此更加可靠。此外,不仅基于 React 的应用更易扩展,我们还发现团队规模也更易扩展。
凭借 Web 的快速迭代周期,我们已用 React 构建了诸多出色产品,包括 Facebook.com 的许多组件。同时我们还在 React 基础上构建了 Relay 等卓越的 JavaScript 框架,极大简化了大规模数据获取。当然,Web 只是故事的一部分。Facebook 还拥有基于割裂的专有技术栈构建的 Android 和 iOS 应用。多平台开发不仅分裂了我们的工程组织,也仅是原生移动应用开发困境的冰山一角。
本文为节选。请访问 Facebook Code 阅读全文。