Expo 讲座:Adam 谈导航
来自 Expo 的 Adam Miskiewicz 上周在 Expo 的办公时间里,谈论了移动导航和 ex-navigation React Native 库。
来自 Expo 的 Adam Miskiewicz 上周在 Expo 的办公时间里,谈论了移动导航和 ex-navigation React Native 库。
在应用发布到应用商店之后,国际化是进一步扩大受众范围的下一步。全球有超过 20 个国家和众多人使用从右到左 (RTL) 语言。因此,让你的应用支持 RTL 对他们来说是必要的。
我们很高兴地宣布,React Native 已得到改进,以支持 RTL 布局。这已在今天的 react-native master 分支中提供,并将包含在下一个 RC 版本中:v0.33.0-rc。
这涉及到对 RN 使用的核心布局引擎 css-layout 和 RN 核心实现进行更改,以及对特定的 OSS JS 组件进行更改以支持 RTL。
为了在生产环境中对 RTL 支持进行压力测试,最新版本的 Facebook Ads Manager 应用(首个跨平台 100% RN 应用)现已提供阿拉伯语和希伯来语版本,支持 iOS 和 Android 的 RTL 布局。以下是这些 RTL 语言的应用外观:

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

这包括:
left 和 right 映射到 shadow nodes 的 start 和 end通过此更新,当您允许您的应用程序使用 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 文件中将 android:supportsRtl="true" 添加到 <application> 元素中。
现在,当您重新编译应用程序并将设备语言更改为 RTL 语言(例如阿拉伯语或希伯来语)时,您的应用程序布局应该会自动更改为 RTL。
通常,大多数组件已经支持 RTL,例如:
然而,有几种情况需要注意,您将需要 I18nManager。在 I18nManager 中,有一个常量 isRTL 用于指示应用布局是否为 RTL,以便您可以根据布局进行必要的更改。
如果您的组件有图标或图像,它们在 LTR 和 RTL 布局中的显示方式将相同,因为 RN 不会翻转您的源图像。因此,您应该根据布局样式翻转它们。
以下是根据方向翻转图标的两种方法:
给图像组件添加 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 布局相反。目前,在 RN 中,手势和动画不在 RN 核心代码层面支持,而是在组件层面支持。好消息是,其中一些组件今天已经支持 RTL,例如 SwipeableRow 和 NavigationExperimental。然而,其他带有手势的组件将需要手动支持 RTL。
一个说明手势 RTL 支持的绝佳示例是 SwipeableRow。


// 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”,代码中的 right 在屏幕上变为“left”。这很方便,因为你不需要过多地更改你的产品代码,但这意味着无法在代码中指定“真正的左”或“真正的右”。将来,允许组件独立于语言控制其方向可能是必要的。
使手势和动画的 RTL 支持更具开发人员友好性
目前,使手势和动画与 RTL 兼容仍需要一些编程工作。未来,理想的做法是找到一种方法,使手势和动画的 RTL 支持更具开发人员友好性。
请查看 RNTester 中的 RTLExample,以更多地了解 RTL 支持,并告诉我们您的体验!
最后,感谢您的阅读!我们希望 React Native 对 RTL 的支持能帮助您为国际受众发展您的应用程序!
上周,我有机会参加了在 Zynga 旧金山办公室举办的 React Native 技术交流会。近 200 人参会,这是一个结识附近其他对 React Native 感兴趣的开发者的绝佳场所。

我特别感兴趣的是了解 React 和 React Native 如何在 Zynga、Netflix 和 Airbnb 等公司中使用。当晚的议程如下:
但首先,活动以一个简短的介绍和近期新闻的简要回顾开始
react-native link 代替 rnpm link 来 安装具有原生依赖的库。如果 这些技术交流会中的一场 在你附近举行,我强烈建议参加!
第一轮新闻之后,今晚的主办方 Zynga 进行了简短介绍。Abhishek Chadha 谈到了他们如何使用 React 快速为移动设备开发新体验的原型,并演示了一个类似“你画我猜”应用的快速原型。他们使用与 React Native 类似的方法,通过桥接提供对原生 API 的访问。Abhishek 在演示中使用了设备的摄像头拍摄观众的照片,然后在某个人的头上画了一顶帽子,以此展示了这一点。
接下来是当晚的第一个主题演讲。Netflix 高级软件工程师 Clarence Leung 发表了他关于“为 React Native 设计 API”的演讲。他首先指出了人们可能开发的两种主要类型的库:组件,如标签栏和日期选择器;以及提供原生服务访问的库,如相机胶卷或应用内支付。在为 React Native 构建库时,有两种方法可以采用。
每种方法都有其自身的考量,由您决定哪种最适合您的需求。
方法一
作为平台特定组件的例子,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 在现有代码库中的应用。我Already知道使用 React Native 从头开始编写新应用程序有多容易,所以我非常想听听 Airbnb 在他们现有原生应用程序中采用 React Native 的经验。
Leland 首先谈到了绿地应用和棕地应用。绿地项目意味着无需考虑任何先前的工作而开始一个项目。这与棕地项目形成对比,在棕地项目中,您需要考虑现有项目的需求、开发流程以及所有团队的各种需求。
当您在一个绿地应用上工作时,React Native CLI 会为 Android 和 iOS 设置一个单一的仓库,一切都正常工作。Airbnb 使用 React Native 的第一个挑战是 Android 和 iOS 应用各自拥有自己的仓库。多仓库公司在采用 React Native 之前需要克服一些障碍。
为了解决这个问题,Airbnb 首先为 React Native 代码库设置了一个新的仓库。他们使用持续集成服务器将 Android 和 iOS 仓库镜像到这个新仓库中。测试运行并构建捆绑包后,构建工件会同步回 Android 和 iOS 仓库。这允许移动工程师在不改变其开发环境的情况下处理原生代码。移动工程师无需安装 npm、运行打包器或记住构建 JavaScript 捆绑包。编写实际 React Native 代码的工程师无需担心在 Android 和 iOS 之间同步他们的代码,因为他们直接在 React Native 仓库上工作。
这确实带来了一些缺点,主要是他们无法进行原子更新。需要原生代码和 JavaScript 代码组合的更改将需要三个独立的拉取请求,所有这些都必须仔细合并。为了避免冲突,如果在构建开始后 master 分支发生更改,CI 将无法将更改同步回 Android 和 iOS 仓库。这在高提交频率的日子(例如发布新版本时)会导致长时间的延迟。
Airbnb 从那时起已转向单一代码库方法。幸运的是,这已经考虑在内,一旦 Android 和 iOS 团队对使用 React Native 感到满意,他们便乐于加速向单一代码库的迁移。
这解决了他们在使用分离仓库方法时遇到的多数问题。Leland 确实指出,这确实会给版本控制服务器带来更大的压力,这对于小型公司来说可能是一个问题。

Leland 演讲的后半部分聚焦于一个我非常关心的话题:React Native 中的导航问题。他谈到了 React Native 中大量的第一方和第三方导航库。NavigationExperimental 被提及为一个看起来很有前景的方案,但最终并不适合他们的用例。
事实上,现有的导航库似乎都不适用于棕地应用。棕地应用要求导航状态完全由原生应用拥有。例如,如果用户会话在 React Native 视图显示时过期,原生应用应该能够接管并根据需要显示登录屏幕。
Airbnb 也希望避免在过渡过程中用 JavaScript 版本替换原生导航栏,因为这种效果可能会让人感到不协调。最初,他们将自己限制在模态呈现的视图上,但这显然在他们的应用程序中更广泛地采用 React Native 时带来了问题。
他们决定需要自己的库。这个库叫做 airbnb-navigation。该库尚未开源,因为它与 Airbnb 的代码库紧密相关,但他们希望在今年年底前发布它。
我不会详细介绍该库的 API,但以下是一些要点:
还有一些注意事项需要牢记:
Leland 的演讲之后还有问答环节。总的来说,Airbnb 对 React Native 很满意。他们对使用 Code Push 来修复任何问题而无需通过应用商店感兴趣,他们的工程师喜欢 Live Reload,因为他们不必在每次细微更改后等待原生应用重建。
活动以一些额外的 React Native 新闻结束

聚会提供了一个很好的机会,可以与社区中的其他开发者见面并向他们学习。我期待将来参加更多的 React Native 聚会。如果您参加了其中一个,请留意我,并告诉我我们如何才能让 React Native 更好地为您服务!
拥有卓越开发者体验的其中一部分就是拥有出色的文档。创建良好文档需要付出很多努力——理想的文档应简洁、有帮助、准确、完整且令人愉悦。最近我们一直在根据您的反馈努力改进文档,我们想分享一些我们已做出的改进。
当您学习一个新库、一种新编程语言或一个新框架时,总有一个美好的时刻,当您第一次编写一些代码,尝试运行它,看看它是否有效……然后它确实有效。您创造了一些真实的东西。我们希望将这种身临其境的体验直接融入到我们的文档中。就像这样
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);
我们认为这些内联示例,使用 react-native-web-player 模块,并在 Devin Abbott 的帮助下,是学习 React Native 基础知识的绝佳方式,并且我们已更新了 面向新 React Native 开发者的教程,尽可能地使用它们。快去看看吧 - 如果您曾经好奇修改一小段示例代码会发生什么,这是一种很好的探索方式。此外,如果您正在构建开发者工具,并希望在自己的网站上展示实时的 React Native 示例,react-native-web-player 可以轻松实现这一点。
核心模拟引擎由 Nicolas Gallagher 的 react-native-web 项目提供,该项目提供了一种在 Web 上显示 React Native 组件(如 Text 和 View)的方法。如果您有兴趣构建共享大部分代码库的移动和 Web 体验,请查看 react-native-web。
在 React Native 的某些部分,有多种方法可以完成事情,我们收到了反馈,认为我们可以提供更好的指导。
我们有一个新的 导航指南,它比较了不同的方法,并就您应该使用什么提供了建议 - Navigator、NavigatorIOS、NavigationExperimental。从中长期来看,我们正致力于改进和整合这些接口。短期内,我们希望一个更好的指南能让您的生活更轻松。
我们还有一个新的 处理触摸的指南,它解释了一些创建按钮类界面的基本知识,并简要总结了处理触摸事件的不同方法。
我们还改进了 Flexbox 领域。这包括关于如何 使用 Flexbox 处理布局 和如何控制 组件尺寸 的教程。它还包括一个不太吸引人但希望有所帮助的 控制 React Native 中布局的所有 prop 的列表。
当您开始在您的机器上设置 React Native 开发环境时,确实需要进行大量的安装和配置。让安装成为一个真正有趣和令人兴奋的体验是很困难的,但我们至少可以使其尽可能快速和无痛。
我们构建了一个 新的入门工作流程,允许您预先选择您的开发操作系统和移动操作系统,从而提供一个简洁的地方,包含所有设置说明。我们还对安装过程进行了审查,以确保一切正常,并确保每个决策点都有清晰的建议。在对我们的无辜同事进行测试后,我们确信这是一项改进。
我们还改进了 将 React Native 集成到现有应用中的指南。许多使用 React Native 的大型应用,例如 Facebook 应用本身,实际上是部分使用 React Native 构建,部分使用常规开发工具构建的。我们希望本指南能让更多人更轻松地以这种方式构建应用。
您的反馈让我们知道我们应该优先考虑什么。我知道有些人会读这篇博客文章并想“更好的文档?哼。X 的文档仍然是垃圾!”。这很好——我们需要这种动力。提供反馈的最佳方式取决于反馈的类型。
如果您在文档中发现错误,例如不准确的描述或无法正常工作的代码,请 提交一个 issue。将其标记为 "Documentation",以便更容易地将其路由给相关人员。
如果没有具体的错误,但文档中的某些内容根本上令人困惑,那么它不适合在 GitHub issue 中提出。相反,请在 Canny 上发布关于需要改进的文档区域的反馈。这有助于我们在进行指南编写等更普遍的工作时确定优先级。
感谢您阅读到这里,也感谢您使用 React Native!
React Native 开源一年了。最初只是几个工程师的一个想法,如今已经成为了 Facebook 内部及其他公司产品团队使用的框架。今天在 F8 大会上,我们宣布微软将 React Native 引入 Windows 生态系统,开发者将有机会在 Windows PC、手机和 Xbox 上构建 React Native 应用。它还将提供开源工具和服务,例如 Visual Studio Code 的 React Native 扩展和 CodePush,以帮助开发者在 Windows 平台上创建 React Native 应用。此外,三星正在为其混合平台构建 React Native,这将使开发者能够为数百万台智能电视以及移动和可穿戴设备构建应用。我们还发布了 React Native 的 Facebook SDK,使开发者可以更轻松地将登录、分享、应用分析和 Graph API 等 Facebook 社交功能集成到他们的应用中。一年时间里,React Native 改变了在各大平台上进行开发的方式。
这是一段史诗般的旅程——但我们才刚刚开始。以下回顾了 React Native 自一年前开源以来是如何成长和演变的,我们在此过程中遇到的一些挑战,以及我们对未来的展望。
这只是节选。请在 Facebook Code 上阅读全文。
React Native 允许你使用 React 和 Relay 的声明式编程模型,用 JavaScript 构建 Android 和 iOS 应用。这使得代码更简洁、易于理解;无需编译周期即可快速迭代;并且易于在多个平台之间共享代码。你可以更快地发布产品,并专注于真正重要的细节,让你的应用看起来和感觉都棒极了。优化性能是其中的重要部分。以下是我们如何让 React Native 应用启动速度加快一倍的故事。
应用运行速度更快,内容加载更快,这意味着人们有更多时间与其互动,流畅的动画使应用使用起来更令人愉悦。在新兴市场,其中 2011 年的手机 在 2G 网络 上仍然是主流,关注性能可以决定一个应用是否可用。
自 React Native 在 iOS 和 Android 发布以来,我们一直在改进列表视图滚动性能、内存效率、UI 响应能力和应用启动时间。启动会给应用留下第一印象,并对框架的所有部分构成压力,因此它是最令人满意且最具挑战性的问题。
这是节选。在 Facebook Code 上阅读其余内容。
React Native 的目标是为您提供最佳的开发者体验。其中很重要的一部分是您保存文件到看到更改所需的时间。我们的目标是使这个反馈循环在应用程序增长时也能保持在1秒以内。
我们通过以下三个主要功能接近这个理想状态:
此时,开发人员的瓶颈不再是重新加载应用所需的时间,而是丢失了应用的状态。一个常见场景是处理一个离启动屏幕有多个屏幕距离的功能。每次重新加载时,你都必须一遍又一遍地点击相同的路径才能回到你的功能,这使得周期长达数秒。
热重载的理念是保持应用程序运行,并在运行时注入您编辑的文件的最新版本。这样,您不会丢失任何状态,这在调整 UI 时尤其有用。
一图胜千言。看看实时重载(当前)和热重载(新)之间的区别。
如果您仔细观察,您会发现可以从红框中恢复,并且还可以开始导入以前不存在的模块,而无需完全重新加载。
警告:由于 JavaScript 是一种非常注重状态的语言,热重载无法完美实现。在实践中,我们发现当前的设置对于大量常见用例都运行良好,并且在出现问题时始终可以使用完全重载。
热重载在 0.22 版本中可用,您可以启用它:
现在我们已经了解了为什么需要它以及如何使用它,有趣的部分开始了:它实际是如何工作的。
热重载基于一个名为 热模块替换 (Hot Module Replacement),简称 HMR 的功能构建。它最初由 webpack 引入,我们在 React Native Packager 中实现了它。HMR 使 Packager 能够监视文件更改,并将 HMR 更新发送到应用程序中包含的精简 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` 最终被 require 时,导出的函数会与 `time` 的更改一起执行(步骤 2)。

现在,假设 `log` 的代码将 `time` 作为顶层 `require`。
const time = require('./time'); // top level require
// log.js
function log(message) {
console.log(`[${time()}] ${message}`);
}
module.exports = log;
当需要`log`时,运行时将缓存其导出和`time`的导出(步骤1)。然后,当`time`被修改时,HMR进程不能简单地在替换`time`的代码后结束。如果这样做,当`log`执行时,它将使用`time`的缓存副本(旧代码)来执行。
为了让 `log` 接收 `time` 的更改,我们需要清除其缓存的导出,因为其依赖的模块之一已被热交换(步骤 3)。最后,当 `log` 再次被请求时,其工厂函数将被执行,请求 `time` 并获取其新代码。

React Native 中的 HMR 通过引入 hot 对象来扩展模块系统。这个 API 基于 webpack 的 API。hot 对象公开了一个名为 accept 的函数,它允许你定义一个回调函数,当模块需要热交换时,该回调函数将被执行。例如,如果我们像下面这样更改 time 的代码,每次保存 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` 执行相同的操作并在那里结束,因为没有模块依赖于它。
为了遍历依赖树,运行时从 Packager 接收 HMR 更新中的反向依赖树。对于这个例子,运行时将接收一个像这样的 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 组件创建一个代理。代理负责持有组件的状态,并将生命周期方法委托给实际的组件,而这些组件是我们热重载的对象。
除了创建代理组件外,转换还定义了 `accept` 函数,其中包含一段强制 React 重新渲染组件的代码。通过这种方式,我们可以在不丢失任何应用程序状态的情况下热重载渲染代码。
React Native 附带的默认 transformer 使用 babel-preset-react-native,它被 配置 为使用 react-transform,就像你在使用 webpack 的 React Web 项目中会使用它一样。
要在 Redux store 上启用热重载,你只需要像在 Redux store 上启用热重载一样,使用 HMR API,就像你在使用 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,我们有机会重新思考构建应用程序的方式,以创造出色的开发者体验。热重载只是其中一部分,我们还能做些什么疯狂的“黑科技”来做得更好呢?
随着 React 在 Web 和 React Native 在移动端的推出,我们为开发者提供了一个新的前端框架来构建产品。构建健壮产品的一个关键方面是确保任何人都可以使用它,包括视力受损或其他残疾人士。React 和 React Native 的无障碍 API 使你能够让任何基于 React 的体验可供使用辅助技术的人使用,例如盲人和视障人士的屏幕阅读器。
在这篇文章中,我们将重点关注 React Native 应用程序。我们设计的 React 无障碍 API 在外观和感觉上与 Android 和 iOS API 相似。如果你之前开发过 Android、iOS 或 Web 的无障碍应用程序,你将对 React AX API 的框架和命名感到熟悉。例如,你可以使 UI 元素可访问(因此暴露给辅助技术),并使用 `accessibilityLabel` 为元素提供字符串描述
<View accessible={true} accessibilityLabel=”This is simple view”>
让我们通过查看 Facebook 自己的一个 React 驱动产品:广告管理应用,来了解 React AX API 的一个稍微复杂一些的应用。
这是摘录。请访问 Facebook Code 阅读全文。
今年早些时候,我们推出了 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 上阅读全文。
两年前,我们向世界介绍了 React,自那时以来,它在 Facebook 内外部都取得了令人瞩目的增长。如今,尽管没有人被迫使用它,但 Facebook 新的 Web 项目通常会以某种形式使用 React 构建,并且它正在被行业广泛采用。工程师们每天都在选择使用 React,因为它能让他们花费更多时间专注于产品,而不是与框架斗争。然而,直到我们使用 React 构建了一段时间后,我们才开始理解它为何如此强大。
React 强制我们将应用程序分解成离散的组件,每个组件代表一个单一视图。这些组件使得产品迭代更加容易,因为我们无需在更改其中一部分时将整个系统都记在脑中。但更重要的是,React 用声明式 API 封装了 DOM 的命令式、可变 API,这提高了抽象级别并简化了编程模型。我们发现,使用 React 构建时,我们的代码更具可预测性。这种可预测性使我们能够自信地更快迭代,因此我们的应用程序也更加可靠。此外,使用 React 构建的应用程序不仅更容易扩展,我们还发现团队本身的规模也更容易扩展。
结合 Web 快速的迭代周期,我们能够用 React 构建一些很棒的产品,包括 Facebook.com 的许多组件。此外,我们在 React 之上构建了惊人的 JavaScript 框架,例如 Relay,它使我们能够极大地简化大规模数据获取。当然,Web 只是故事的一部分。Facebook 还拥有广泛使用的 Android 和 iOS 应用,这些应用构建在不连贯、专有的技术栈之上。不得不在多个平台之上构建我们的应用程序,这分裂了我们的工程组织,但这只是使原生移动应用程序开发困难的因素之一。
这是一个节选。请在 Facebook Code 阅读其余文章。