跳至主要内容

包含“工程”标签的 26 篇文章

查看所有标签

介绍 Create React Native App

·阅读时间:2 分钟
Adam Perry
Expo 软件工程师

今天,我们宣布发布 Create React Native App:一个新工具,它使 React Native 项目的入门变得更加容易!它深受 Create React App 设计的启发,并且是 FacebookExpo(以前称为 Exponent)之间合作的产物。

许多开发人员在安装和配置 React Native 当前的原生构建依赖项方面遇到困难,尤其是在 Android 上。使用 Create React Native App,无需使用 Xcode 或 Android Studio,并且可以使用 Linux 或 Windows 为您的 iOS 设备进行开发。这是通过使用 Expo 应用实现的,该应用加载并运行用纯 JavaScript 编写的 CRNA 项目,无需编译任何原生代码。

尝试创建一个新项目(如果已安装,请替换为合适的 yarn 命令)

$ npm i -g create-react-native-app
$ create-react-native-app my-project
$ cd my-project
$ npm start

这将启动 React Native 打包程序并打印一个 QR 码。在 Expo 应用 中打开它以加载您的 JavaScript。对 console.log 的调用将转发到您的终端。您也可以使用任何标准的 React Native API 以及 Expo SDK

原生代码怎么样?

许多 React Native 项目都具有需要编译的 Java 或 Objective-C/Swift 依赖项。Expo 应用确实包含了摄像头、视频、联系人等 API,并且捆绑了一些流行的库,例如 Airbnb 的 react-native-mapsFacebook 身份验证。但是,如果您需要 Expo 未捆绑的原生代码依赖项,那么您可能需要为此配置自己的构建。就像 Create React App 一样,CRNA 支持“弹出”。

您可以运行 npm run eject 以获得一个与 react-native init 生成的项目非常相似的项目。此时,您将需要 Xcode 和/或 Android Studio,就像您从 react-native init 开始一样,使用 react-native link 添加库将起作用,并且您可以完全控制原生代码编译过程。

问题?反馈?

Create React Native App 现在已经足够稳定,可以供普遍使用,这意味着我们非常渴望了解您使用它的体验!您可以在 Twitter 上找到我,或在 GitHub 代码库 上提交问题。非常欢迎您提交拉取请求!

为 Animated 使用 Native Driver

·阅读时间:7 分钟
Janic Duplessis
App & Flow 软件工程师

在过去的一年里,我们一直在努力改进使用 Animated 库的动画性能。动画对于创造出色的用户体验非常重要,但也很难做好。我们希望让开发人员能够轻松创建高性能动画,而无需担心其某些代码导致延迟。

这是什么?

Animated API 的设计考虑了一个非常重要的约束,它是可序列化的。这意味着我们可以将动画的所有信息发送到原生代码,甚至在它开始之前,并允许原生代码在 UI 线程上执行动画,而无需在每一帧都通过桥接器。这非常有用,因为一旦动画开始,JS 线程可能会被阻塞,但动画仍将流畅运行。在实践中,这种情况经常发生,因为用户代码在 JS 线程上运行,而 React 渲染也可能长时间锁定 JS。

一些历史…

该项目大约在一年前开始,当时 Expo 在 Android 上构建了 li.st 应用。Krzysztof Magiera 被委托在 Android 上构建初始实现。最终效果很好,li.st 是第一个使用 Animated 的原生驱动动画发布的应用。几个月后,Brandon Withrow 在 iOS 上构建了初始实现。之后,Ryan Gomba 和我一起添加了缺失的功能,例如对 Animated.event 的支持,以及在生产应用中使用时发现的错误修复。这确实是一项社区努力,我要感谢所有参与其中的人,以及赞助了大部分开发工作的 Expo。现在,它被 React Native 中的 Touchable 组件以及新发布的 React Navigation 库中的导航动画使用。

它是如何工作的?

首先,让我们看看当前使用 Animated 和 JS 驱动程序动画是如何工作的。使用 Animated 时,您声明一个节点图,表示您想要执行的动画,然后使用驱动程序使用预定义曲线更新 Animated 值。您还可以通过将 Animated 值连接到 View 的事件(使用 Animated.event)来更新它。

以下是动画步骤的细分以及发生位置

  • JS:动画驱动程序使用 requestAnimationFrame 在每一帧上执行并更新它驱动的值,使用基于动画曲线的计算出的新值。
  • JS:计算中间值并传递到附加到 View 的 props 节点。
  • JS:使用 setNativeProps 更新 View
  • JS 到原生桥接器。

  • 原生:UIViewandroid.View 被更新。

正如你所见,大部分工作发生在 JS 线程上。如果 JS 线程被阻塞,动画将会丢帧。并且,它需要在每一帧都通过 JS 到原生的桥接来更新原生视图。

原生驱动所做的是将所有这些步骤转移到原生端。由于 Animated 会生成一个动画节点图,它可以在动画开始时仅序列化一次并发送到原生端,从而无需回调到 JS 线程;原生代码可以在每一帧直接在 UI 线程上更新视图。

这是一个关于如何序列化动画值和插值节点的例子(不是确切的实现,只是一个例子)。

创建原生值节点,这是将要被动画化的值。

NativeAnimatedModule.createNode({
id: 1,
type: 'value',
initialValue: 0,
});

创建原生插值节点,它告诉原生驱动如何插值。

NativeAnimatedModule.createNode({
id: 2,
type: 'interpolation',
inputRange: [0, 10],
outputRange: [10, 0],
extrapolate: 'clamp',
});

创建原生属性节点,它告诉原生驱动它所附加到的视图上的哪个属性。

NativeAnimatedModule.createNode({
id: 3,
type: 'props',
properties: ['style.opacity'],
});

将节点连接在一起。

NativeAnimatedModule.connectNodes(1, 2);
NativeAnimatedModule.connectNodes(2, 3);

将属性节点连接到一个视图。

NativeAnimatedModule.connectToView(3, ReactNative.findNodeHandle(viewRef));

有了这些,原生动画模块就拥有了直接更新原生视图所需的所有信息,而无需转到 JS 计算任何值。

剩下的就是通过指定我们想要的动画曲线类型和要更新的动画值来实际启动动画。通过预先在 JS 中计算动画的每一帧,也可以简化时间动画,从而使原生实现更小。

NativeAnimatedModule.startAnimation({
type: 'timing',
frames: [0, 0.1, 0.2, 0.4, 0.65, ...],
animatedValueId: 1,
});

现在,以下是动画运行时发生的情况的细分。

  • 原生:原生动画驱动使用 CADisplayLinkandroid.view.Choreographer 在每一帧执行并使用它根据动画曲线计算的新值更新它驱动的值。
  • 原生:计算中间值并将其传递给附加到原生视图的属性节点。
  • 原生:UIViewandroid.View 被更新。

正如你所见,不再有 JS 线程,也不再有桥接,这意味着更快的动画!🎉🎉

如何在我的应用中使用它?

对于普通动画,答案很简单,只需在启动动画时将 useNativeDriver: true 添加到动画配置中。

之前

Animated.timing(this.state.animatedValue, {
toValue: 1,
duration: 500,
}).start();

之后

Animated.timing(this.state.animatedValue, {
toValue: 1,
duration: 500,
useNativeDriver: true, // <-- Add this
}).start();

动画值仅与一个驱动程序兼容,因此,如果在某个值的动画开始时使用原生驱动程序,请确保该值的每个动画也使用原生驱动程序。

它也适用于 Animated.event,如果你有一个必须跟随滚动位置的动画,这非常有用,因为如果没有原生驱动程序,它将始终比手势滞后一帧,这是由于 React Native 的异步特性导致的。

之前

<ScrollView
scrollEventThrottle={16}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.animatedValue } } }]
)}
>
{content}
</ScrollView>

之后

<Animated.ScrollView // <-- Use the Animated ScrollView wrapper
scrollEventThrottle={1} // <-- Use 1 here to make sure no events are ever missed
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.animatedValue } } }],
{ useNativeDriver: true } // <-- Add this
)}
>
{content}
</Animated.ScrollView>

注意事项

并非所有可以使用 Animated 执行的操作都当前支持原生 Animated。主要的限制是,你只能动画化非布局属性,例如 transformopacity 可以工作,但 Flexbox 和位置属性不行。另一个限制是 Animated.event,它仅适用于直接事件,而不适用于冒泡事件。这意味着它不适用于 PanResponder,但适用于 ScrollView#onScroll 之类的东西。

原生 Animated 也已经成为 React Native 的一部分有一段时间了,但从未被记录在案,因为它被认为是实验性的。因此,如果你想使用此功能,请确保你正在使用最新版本的 React Native (0.40+)。

资源

有关动画的更多信息,我建议观看 此演讲,演讲者为 Christopher Chedeau

如果你想深入了解动画以及如何将动画卸载到原生端以改善用户体验,还可以观看 此演讲,演讲者为 Krzysztof Magiera

React Native 应用的从右到左布局支持

·阅读时间:7 分钟
Mengjue (Mandy) Wang
Facebook 软件工程师实习生

在将应用程序发布到应用商店后,国际化是进一步扩大受众范围的下一步。全球超过 20 个国家/地区和众多人群使用从右到左 (RTL) 语言。因此,使你的应用程序支持 RTL 对他们来说是必要的。

我们很高兴地宣布,React Native 已经改进以支持 RTL 布局。这现在可在 react-native 的 master 分支中使用,并且将在下一个 RC 版本中可用:v0.33.0-rc

这涉及更改 css-layout(RN 使用的核心布局引擎)和 RN 核心实现,以及支持 RTL 的特定开源 JS 组件。

为了在生产环境中测试 RTL 支持,最新版本的 Facebook Ads Manager 应用程序(第一个跨平台 100% RN 应用程序)现在已提供阿拉伯语和希伯来语版本,并且这两个版本都提供了适用于 iOSAndroid 的 RTL 布局。以下是这些 RTL 语言中的外观

RN 中 RTL 支持的概述变更

css-layout 已经有了布局的 startend 概念。在从左到右 (LTR) 布局中,start 表示 leftend 表示 right。但在 RTL 中,start 表示 rightend 表示 left。这意味着我们可以使 RN 依赖于 startend 计算来计算正确的布局,其中包括 positionpaddingmargin

此外,css-layout 已经使每个组件的方向继承自其父组件。这意味着,我们只需将根组件的方向设置为 RTL,整个应用程序就会翻转。

下图描述了高级别的更改

这些包括

通过此更新,当你允许你的应用程序使用 RTL 布局时

  • 每个组件的布局都会水平翻转
  • 如果使用 RTL 就绪的开源组件,则某些手势和动画将自动具有 RTL 布局
  • 可能需要最少的额外工作才能使你的应用程序完全 RTL 就绪

使应用程序 RTL 就绪

  1. 要支持 RTL,你应首先将 RTL 语言包添加到你的应用程序中。

    • 请参阅来自 iOSAndroid 的常规指南。
  2. 通过在原生代码的开头调用 allowRTL() 函数来允许你的应用程序使用 RTL 布局。我们提供此实用程序仅在你的应用程序准备就绪时才应用于 RTL 布局。这是一个示例

    iOS

    // in AppDelegate.m
    [[RCTI18nUtil sharedInstance] allowRTL:YES];

    Android

    // in MainActivity.java
    I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
    sharedI18nUtilInstance.allowRTL(context, true);
  3. 对于 Android,你需要在 AndroidManifest.xml 文件中的 <application> 元素中添加 android:supportsRtl="true"

现在,当你重新编译你的应用程序并将设备语言更改为 RTL 语言(例如阿拉伯语或希伯来语)时,你的应用程序布局应自动更改为 RTL。

编写 RTL 就绪组件

通常,大多数组件都已经 RTL 就绪,例如

  • 从左到右布局
  • 从右到左布局

但是,有一些情况需要注意,对于这些情况,你需要使用 I18nManager。在 I18nManager 中,有一个常量 isRTL 用于判断应用程序的布局是 RTL 还是 LTR,以便你可以根据布局进行必要的更改。

具有方向含义的图标

如果你的组件包含图标或图像,它们将在 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,例如 SwipeableRowNavigationExperimental。但是,其他具有手势的组件需要手动支持 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 就绪应用程序

即使在初始 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 支持应该涵盖应用的大部分用户体验,但目前存在一些限制。

  • 文本对齐行为在 Android 和 iOS 上有所不同。
    • 在 iOS 上,默认文本对齐取决于活动语言包,它们始终位于同一侧。在 Android 上,默认文本对齐取决于文本内容的语言,例如,英文将左对齐,阿拉伯语将右对齐。
    • 理论上,这应该在平台之间保持一致,但某些用户在使用应用时可能更偏好某种行为。可能需要更多用户体验研究来找出文本对齐的最佳实践。
  • 没有“真正的”左右。

    如前所述,我们将 JS 端的 left/right 样式映射到 start/end,代码中用于 RTL 布局的所有 left 在屏幕上都变成了“right”,而代码中的 right 在屏幕上变成了“left”。这很方便,因为您无需过多更改产品代码,但意味着无法在代码中指定“真正的 left”或“真正的 right”。将来,可能需要允许组件控制其方向,而不管语言如何。

  • 使手势和动画的 RTL 支持更易于开发者使用。

    目前,使手势和动画与 RTL 兼容仍然需要一些编程工作。将来,理想情况下,需要找到一种方法使手势和动画的 RTL 支持更易于开发者使用。

试一试!

查看 RNTester 中的 RTLExample,以了解有关 RTL 支持的更多信息,并告诉我们它对您来说效果如何!

最后,感谢您的阅读!我们希望 React Native 的 RTL 支持能帮助您为国际用户扩展应用!

深入探讨 React Native 性能

·阅读时间:2 分钟
Pieter De Baets
Facebook 软件工程师

React Native 允许您使用 React 和 Relay 的声明式编程模型,用 JavaScript 构建 Android 和 iOS 应用。这将带来更简洁、更容易理解的代码;无需编译周期即可快速迭代;以及跨多个平台轻松共享代码。您可以更快地发布,并专注于真正重要的细节,使您的应用看起来和感觉都棒极了。优化性能是其中很大一部分。以下是我们如何使 React Native 应用启动速度提高两倍的故事。

为什么这么着急?

使用运行速度更快的应用,内容加载速度更快,这意味着人们有更多时间与之交互,流畅的动画使应用使用起来更愉快。在 2011 年级的手机2G 网络占多数的新兴市场,专注于性能可以决定一个应用是否可用。

自从在 iOSAndroid 上发布 React Native 以来,我们一直在改进列表视图滚动性能、内存效率、UI 响应能力和应用启动时间。启动时间决定了应用的第一印象,并给框架的所有部分带来压力,因此它是最值得解决且最具挑战性的问题。

这是一段摘录。在 Facebook 代码 上阅读文章的其余部分。

介绍热重载

·阅读时间:9 分钟
Martín Bigio
Instagram 软件工程师

React Native 的目标是为您提供尽可能最佳的开发体验。其中很大一部分是您保存文件到能够看到更改之间的时间。我们的目标是使这个反馈循环在 1 秒内完成,即使您的应用不断增长。

我们通过三个主要功能接近了这一理想状态。

  • 使用 JavaScript 作为语言,没有较长的编译周期时间。
  • 实现了一个名为 Packager 的工具,它将 es6/flow/jsx 文件转换为 VM 可以理解的普通 JavaScript。它被设计为一个服务器,在内存中保存中间状态以启用快速增量更改,并使用多个核心。
  • 构建了一个名为 Live Reload 的功能,该功能在保存时重新加载应用。

此时,开发人员的瓶颈不再是重新加载应用所需的时间,而是丢失应用的状态。一个常见的场景是处理一个距离启动屏幕多个屏幕的功能。每次重新加载时,您都必须一遍又一遍地点击相同的路径才能返回到您的功能,从而使循环时间延长几秒钟。

热重载

热重载背后的理念是在运行时保持应用运行并注入您编辑的文件的新版本。这样,您就不会丢失任何状态,这在您调整 UI 时特别有用。

一张图片胜过千言万语。查看 Live Reload(当前)和 Hot Reload(新)之间的区别。

如果您仔细观察,您会注意到可以从红色框中恢复,并且还可以开始导入之前不存在的模块,而无需进行完全重新加载。

警告:由于 JavaScript 是一种非常有状态的语言,因此无法完美地实现热重载。在实践中,我们发现当前设置对于大量常见用例都能很好地工作,并且如果出现任何问题,始终可以使用完全重新加载。

从 0.22 版本开始提供热重载,您可以启用它。

  • 打开开发者菜单。
  • 点击“启用热重载”。

简而言之的实现

既然我们已经了解了为什么要使用它以及如何使用它,那么有趣的部分开始了:它实际上是如何工作的。

热重载构建在 热模块替换(或 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。此时,logtime 的工厂函数均未执行,因此尚未缓存任何导出。然后,用户修改 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 作为顶级 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 并获取其新代码。

HMR API

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 运行时

如前所述,有时仅仅接受 HMR 更新是不够的,因为使用正在进行热交换的模块的模块可能已经执行并缓存了其导入。例如,假设电影应用示例的依赖树有一个顶级 MovieRouter,它依赖于 MovieSearchMovieScreen 视图,而这两个视图又依赖于前面示例中的 logtime 模块。

如果用户访问了电影搜索视图但没有访问其他视图,则除 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 组件在使用热重载方面稍微复杂一些。问题在于我们无法简单地用新代码替换旧代码,因为这样会导致组件状态丢失。对于 React Web 应用程序,Dan Abramov 实现了一个 babel 转换,它使用 webpack 的 HMR API 来解决此问题。简而言之,他的解决方案是在转换时为每个 React 组件创建一个代理。代理保存组件的状态并将生命周期方法委托给实际的组件,而我们热重载的就是这些实际组件。

除了创建代理组件之外,转换还会定义accept函数,其中包含一段代码来强制 React 重新渲染组件。这样,我们就可以热重载渲染代码,而不会丢失任何应用程序的状态。

React Native 附带的默认转换器使用babel-preset-react-native,它被配置为以与在使用 webpack 的 React Web 项目中相同的方式使用react-transform

Redux 存储

要在Redux 存储上启用热重载,您只需类似于在使用 webpack 的 Web 项目中那样使用 HMR API 即可。

// 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 不知道如何接受自身,因此它会查找所有引用它的模块并尝试接受它们。最终,流程将到达单个存储,即configureStore模块,它将接受 HMR 更新。

结论

如果您有兴趣帮助改进热重载,我鼓励您阅读Dan Abramov 关于热重载未来的文章并做出贡献。例如,Johny Days 将使其与多个连接的客户端一起工作。我们依靠大家来维护和改进此功能。

使用 React Native,我们有机会重新思考构建应用程序的方式,以使其成为出色的开发体验。热重载只是拼图的一部分,我们还能做哪些疯狂的技巧来使其变得更好?

使 React Native 应用可访问

·阅读时间:2 分钟
Georgiy Kassabli
Facebook 软件工程师

随着 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上阅读文章的其余部分。