跳至主要内容

2018 年 React Native 现状

·阅读时间:5 分钟
Sophie Alpert
Facebook React 工程经理

自从我们上次发布关于 React Native 的状态更新以来,已经有一段时间了。

在 Facebook,我们比以往任何时候都更多地使用 React Native,并且用于许多重要的项目。我们最受欢迎的产品之一是 Marketplace,这是我们应用中顶级标签之一,每月有 8 亿人使用。自 2015 年创建以来,整个 Marketplace 都是使用 React Native 构建的,包括应用不同部分的 100 多个全屏视图。

我们还在使用 React Native 构建应用的许多新部分。如果您在上个月观看了 F8 主题演讲,您会认出献血、危机应对、隐私快捷方式和健康检查——所有这些都是最近使用 React Native 构建的功能。而且 Facebook 应用之外的项目也使用 React Native。新的 Oculus Go VR 耳机包含 一个配套移动应用,它完全使用 React Native 构建,更不用说 React VR 为耳机本身中的许多体验提供动力了。

当然,我们也使用许多其他技术来构建我们的应用。 LithoComponentKit 是我们在应用中广泛使用的两个库;两者都为构建原生屏幕提供了类似 React 的组件 API。React Native 从来没有目标要取代所有其他技术——我们专注于使 React Native 本身变得更好,但我们很高兴看到其他团队借鉴 React Native 的想法,例如将 即时重载 也带到非 JavaScript 代码中。

架构

当我们在 2013 年启动 React Native 项目时,我们将其设计为在 JavaScript 和原生之间具有单个“桥梁”,该桥梁是异步的、可序列化的和批处理的。就像 React DOM 将 React 状态更新转换为对 DOM API(如 document.createElement(attrs).appendChild())的命令式、可变调用一样,React Native 被设计为返回一个列出要执行的变异的单个 JSON 消息,例如 [["createView", attrs], ["manageChildren", ...]]。我们设计了整个系统,使其永远不会依赖于获取同步响应,并确保该列表中的所有内容都可以完全序列化为 JSON 并返回。我们这样做是为了它赋予我们的灵活性:在此架构之上,我们能够构建像 Chrome 调试 这样的工具,它通过 WebSocket 连接异步运行所有 JavaScript 代码。

在过去的 5 年里,我们发现这些最初的原则使构建某些功能变得更加困难。异步桥意味着您无法将 JavaScript 逻辑直接与许多期望同步答案的原生 API 集成。一个对原生调用进行排队的批处理桥意味着更难以让 React Native 应用调用以原生方式实现的函数。而可序列化的桥意味着不必要的复制,而不是在两个世界之间直接共享内存。对于完全在 React Native 中构建的应用,这些限制通常是可以忍受的。但对于在 React Native 和现有应用代码之间进行复杂集成的应用,它们令人沮丧。

我们正在对 React Native 进行大规模的重新架构,以使框架更加灵活,并更好地与混合 JavaScript/原生应用中的原生基础设施集成。 通过这个项目,我们将应用我们在过去 5 年中学到的经验,并逐步将我们的架构提升到更现代的架构。我们正在重写 React Native 的许多内部组件,但大多数更改都在幕后:现有的 React Native 应用将继续工作,几乎无需更改或无需更改。

为了使 React Native 更加轻量级,并更好地适应现有的原生应用,此重新架构具有三个主要的内部更改。首先,我们正在更改线程模型。与其每个 UI 更新都需要在三个不同的线程上执行工作,不如能够在任何线程上同步调用 JavaScript 以进行高优先级更新,同时仍将低优先级工作移出主线程以保持响应能力。其次,我们正在将 异步渲染 功能集成到 React Native 中,以允许多个渲染优先级并简化异步数据处理。最后,我们正在简化我们的桥梁,使其更快、更轻量级;原生和 JavaScript 之间的直接调用效率更高,并且将使构建像跨语言堆栈跟踪这样的调试工具变得更容易。

一旦这些更改完成,更紧密的集成将成为可能。如今,不可能在没有复杂黑客的情况下合并原生导航和手势处理或 UICollectionView 和 RecyclerView 等原生组件。在我们对线程模型进行更改后,构建此类功能将变得非常简单。

随着这项工作的完成,我们将在今年晚些时候发布更多相关细节。

社区

除了 Facebook 内部社区之外,我们很高兴看到 Facebook 之外有大量蓬勃发展的 React Native 用户和合作者。我们希望更多地支持 React Native 社区,方法是更好地服务 React Native 用户,并使项目更易于贡献。

就像我们的架构更改将有助于 React Native 与其他原生基础设施更简洁地互操作一样,React Native 应该在 JavaScript 方面更精简,以更好地适应 JavaScript 生态系统,其中包括使 VM 和打包程序可交换。我们知道破坏性更改的速度可能难以跟上,因此我们希望找到减少主要版本发布的方法。最后,我们知道有些团队正在寻找有关启动优化等主题的更全面的文档,而我们的专业知识尚未记录在案。预计在未来一年中会看到其中一些变化。

如果您正在使用 React Native,那么您就是我们社区的一员;请继续告诉我们如何才能使 React Native 变得更适合您。

React Native 只是移动开发人员工具箱中的一个工具,但我们坚信它——并且我们每天都在使其变得更好,在过去一年中,来自 500 多位贡献者的 2500 多次提交证明了这一点。

在 React Native 中使用 TypeScript

·阅读时间:8 分钟
Ash Furrow
Artsy 软件工程师

JavaScript!我们都喜欢它。但我们中的一些人也很喜欢类型。幸运的是,有一些选项可以为 JavaScript 添加更强的类型。我最喜欢的是TypeScript,但 React Native 开箱即用地支持Flow。你更喜欢哪一个取决于个人偏好,它们各自都有自己的方法来为 JavaScript 添加类型的魔力。今天,我们将了解如何在 React Native 应用程序中使用 TypeScript。

这篇文章使用 Microsoft 的TypeScript-React-Native-Starter 仓库作为指南。

更新:自从这篇博文发布以来,事情变得更加容易了。你可以通过运行一个命令来替换这篇博文中描述的所有设置步骤

npx react-native init MyAwesomeProject --template react-native-template-typescript

然而,Babel 对 TypeScript 的支持确实有一些限制,上面提到的博文详细介绍了这些限制。这篇博文中概述的步骤仍然有效,Artsy 在生产环境中仍在使用react-native-typescript-transformer,但使用上述命令是启动和运行 React Native 和 TypeScript 的最快方法。如果你需要,你随时可以切换。

无论如何,玩得开心!原始博文继续在下面。

先决条件

因为你可能在多个不同的平台上进行开发,并且针对多种不同类型的设备,所以基本的设置可能会比较复杂。你应该首先确保你可以在没有 TypeScript 的情况下运行一个普通的 React Native 应用程序。请按照React Native 网站上的说明开始。当你成功部署到设备或模拟器后,你就可以开始创建 TypeScript React Native 应用程序了。

你还需要Node.jsnpmYarn

初始化

一旦你尝试了搭建一个普通的 React Native 项目,你就可以开始添加 TypeScript 了。让我们开始吧。

react-native init MyAwesomeProject
cd MyAwesomeProject

添加 TypeScript

下一步是将 TypeScript 添加到你的项目中。以下命令将

  • 将 TypeScript 添加到你的项目中
  • React Native TypeScript Transformer 添加到你的项目中
  • 初始化一个空的 TypeScript 配置文件,我们将在下一步配置它
  • 添加一个空的 React Native TypeScript Transformer 配置文件,我们将在下一步配置它
  • 添加 React 和 React Native 的类型定义

好的,让我们运行这些命令。

yarn add --dev typescript
yarn add --dev react-native-typescript-transformer
yarn tsc --init --pretty --jsx react
touch rn-cli.config.js
yarn add --dev @types/react @types/react-native

tsconfig.json 文件包含 TypeScript 编译器的所有设置。上面命令创建的默认值大多都可以,但打开文件并取消以下行的注释

{
/* Search the config file for the following line and uncomment it. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
}

rn-cli.config.js 包含 React Native TypeScript Transformer 的设置。打开它并添加以下内容

module.exports = {
getTransformModulePath() {
return require.resolve('react-native-typescript-transformer');
},
getSourceExts() {
return ['ts', 'tsx'];
},
};

迁移到 TypeScript

将生成的 App.js__tests_/App.js 文件重命名为 App.tsxindex.js 需要使用 .js 扩展名。所有新文件都应该使用 .tsx 扩展名(或者如果文件不包含任何 JSX,则使用 .ts)。

如果你现在尝试运行应用程序,你可能会遇到类似 object prototype may only be an object or null 的错误。这是由于未能从 React 中导入默认导出以及同一行上的命名导出造成的。打开 App.tsx 并修改文件顶部的导入语句

-import React, { Component } from 'react';
+import React from 'react'
+import { Component } from 'react';

其中一些与 Babel 和 TypeScript 如何与 CommonJS 模块交互的不同之处有关。将来,这两个工具将在相同的行为上稳定下来。

此时,你应该能够运行 React Native 应用程序了。

添加 TypeScript 测试基础设施

React Native 附带了Jest,因此对于使用 TypeScript 测试 React Native 应用程序,我们将希望将ts-jest 添加到我们的 devDependencies 中。

yarn add --dev ts-jest

然后,我们将打开 package.json 并将 jest 字段替换为以下内容

{
"jest": {
"preset": "react-native",
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"transform": {
"^.+\\.(js)$": "<rootDir>/node_modules/babel-jest",
"\\.(ts|tsx)$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"testPathIgnorePatterns": [
"\\.snap$",
"<rootDir>/node_modules/"
],
"cacheDirectory": ".jest/cache"
}
}

这将配置 Jest 使用 ts-jest 运行 .ts.tsx 文件。

安装依赖项类型声明

为了在 TypeScript 中获得最佳体验,我们希望类型检查器能够理解我们依赖项的形状和 API。一些库会发布包含 .d.ts 文件(类型声明/类型定义文件)的包,这些文件可以描述底层 JavaScript 的形状。对于其他库,我们需要在 @types/ npm 范围内显式安装相应的包。

例如,这里我们需要 Jest、React 和 React Native 以及 React Test Renderer 的类型。

yarn add --dev @types/jest @types/react @types/react-native @types/react-test-renderer

我们将这些声明文件包保存到我们的开发依赖项中,因为这是一个 React Native 应用程序,它只在开发期间使用这些依赖项,而不是在运行时使用。如果我们要将库发布到 NPM,我们可能需要将其中一些类型依赖项添加为常规依赖项。

你可以阅读更多关于获取 .d.ts 文件的信息

忽略更多文件

对于你的源代码控制,你将希望开始忽略 .jest 文件夹。如果你使用的是 git,我们可以只在 .gitignore 文件中添加条目。

# Jest
#
.jest/

作为检查点,考虑将你的文件提交到版本控制中。

git init
git add .gitignore # import to do this first, to ignore our files
git add .
git commit -am "Initial commit."

添加组件

让我们向我们的应用程序添加一个组件。让我们创建一个 Hello.tsx 组件。这是一个教学组件,而不是你在应用程序中实际编写的组件,但它是一个非平凡的组件,展示了如何在 React Native 中使用 TypeScript。

创建一个 components 目录并添加以下示例。

// components/Hello.tsx
import React from 'react';
import {Button, StyleSheet, Text, View} from 'react-native';

export interface Props {
name: string;
enthusiasmLevel?: number;
}

interface State {
enthusiasmLevel: number;
}

export class Hello extends React.Component<Props, State> {
constructor(props: Props) {
super(props);

if ((props.enthusiasmLevel || 0) <= 0) {
throw new Error(
'You could be a little more enthusiastic. :D',
);
}

this.state = {
enthusiasmLevel: props.enthusiasmLevel || 1,
};
}

onIncrement = () =>
this.setState({
enthusiasmLevel: this.state.enthusiasmLevel + 1,
});
onDecrement = () =>
this.setState({
enthusiasmLevel: this.state.enthusiasmLevel - 1,
});
getExclamationMarks = (numChars: number) =>
Array(numChars + 1).join('!');

render() {
return (
<View style={styles.root}>
<Text style={styles.greeting}>
Hello{' '}
{this.props.name +
this.getExclamationMarks(this.state.enthusiasmLevel)}
</Text>

<View style={styles.buttons}>
<View style={styles.button}>
<Button
title="-"
onPress={this.onDecrement}
accessibilityLabel="decrement"
color="red"
/>
</View>

<View style={styles.button}>
<Button
title="+"
onPress={this.onIncrement}
accessibilityLabel="increment"
color="blue"
/>
</View>
</View>
</View>
);
}
}

// styles
const styles = StyleSheet.create({
root: {
alignItems: 'center',
alignSelf: 'center',
},
buttons: {
flexDirection: 'row',
minHeight: 70,
alignItems: 'stretch',
alignSelf: 'center',
borderWidth: 5,
},
button: {
flex: 1,
paddingVertical: 0,
},
greeting: {
color: '#999',
fontWeight: 'bold',
},
});

哇!有很多内容,但让我们分解一下

  • 我们不是渲染像 divspanh1 等 HTML 元素,而是渲染像 ViewButton 这样的组件。这些是在不同平台上都能工作的原生组件。
  • 样式使用 React Native 提供的 StyleSheet.create 函数指定。React 的样式表允许我们使用 Flexbox 控制布局,并使用类似于 CSS 中的构造来控制样式。

添加组件测试

现在我们有了组件,让我们尝试测试它。

我们已经安装了 Jest 作为测试运行器。我们将为我们的组件编写快照测试,让我们添加快照测试所需的附加组件

yarn add --dev react-addons-test-utils

现在让我们在 components 目录中创建一个 __tests__ 文件夹,并为 Hello.tsx 添加一个测试

// components/__tests__/Hello.tsx
import React from 'react';
import renderer from 'react-test-renderer';

import {Hello} from '../Hello';

it('renders correctly with defaults', () => {
const button = renderer
.create(<Hello name="World" enthusiasmLevel={1} />)
.toJSON();
expect(button).toMatchSnapshot();
});

第一次运行测试时,它将创建渲染组件的快照并将其存储在 components/__tests__/__snapshots__/Hello.tsx.snap 文件中。当你修改组件时,你需要更新快照并查看更新是否存在意外更改。你可以阅读更多关于测试 React Native 组件的信息在这里

后续步骤

查看官方的React 教程和状态管理库Redux。这些资源在编写 React Native 应用程序时可能会有帮助。此外,你可能还想查看ReactXP,这是一个完全用 TypeScript 编写的组件库,支持 Web 上的 React 以及 React Native。

在更类型安全的 React Native 开发环境中玩得开心!

使用 React Native 构建 - Build.com 应用

·阅读时间:5 分钟
Garrett McCullough
高级移动工程师

Build.com 总部位于加利福尼亚州奇科,是最大的家居装修用品在线零售商之一。该团队拥有 18 年的强大网络中心业务,并于 2015 年开始考虑移动应用程序。由于团队规模较小且原生开发经验有限,构建独特的 Android 和 iOS 应用程序并不实用。相反,我们决定冒险尝试当时非常新的 React Native 框架。我们的初始提交是在 2015 年 8 月 12 日使用 React Native v0.8.0 进行的!我们在 2016 年 10 月 15 日在两个应用商店上线。在过去两年中,我们一直在继续升级和扩展应用程序。我们目前使用的是 React Native 版本 0.53.0。

你可以在https://www.build.com/app查看该应用程序。

功能

我们的应用程序功能齐全,包含你对电子商务应用程序的所有预期:产品列表、搜索和排序、配置复杂产品的能力、收藏夹等。我们接受标准信用卡支付方式以及 PayPal,以及 iOS 用户的 Apple Pay。

一些你可能意想不到的突出功能包括

  1. 约 40 种产品提供 90 种饰面选项的 3D 模型
  2. 增强现实 (AR) 允许用户以 98% 的尺寸精度查看灯具和水龙头在家中的外观。Build.com React Native 应用程序在 Apple App Store 中以 AR 购物为特色!AR 现在可用于 Android 和 iOS!
  3. 协作项目管理功能,允许人们为项目的不同阶段创建购物清单并在选择方面进行协作

我们正在开发许多新的令人兴奋的功能,这些功能将继续改善我们的应用程序体验,包括 AR 沉浸式购物的下一阶段。

我们的开发工作流程

Build.com 允许每个开发人员选择最适合他们的工具。

  • IDE 包括 Atom、IntelliJ、VS Code、Sublime、Eclipse 等。
  • 对于单元测试,开发人员负责为任何新组件创建 Jest 单元测试,并且我们正在努力使用 jest-coverage-ratchet 提高应用程序较旧部分的覆盖率。
  • 我们使用 Jenkins 构建测试版和候选版本。这个流程对我们来说效果很好,但仍然需要大量工作来创建发布说明和其他工件。
  • 集成测试包括一个共享的测试人员池,这些测试人员跨桌面、移动和 Web 工作。我们的自动化工程师正在使用 Java 和 Appium 构建我们的自动化集成测试套件。
  • 工作流程的其他部分包括详细的 eslint 配置、强制执行测试所需属性的自定义规则以及阻止违规更改的预提交钩子。

应用程序中使用的库

Build.com 应用依赖于许多常见的开源库,包括:Redux、Moment、Numeral、Enzyme 以及一些 React Native 桥接模块。我们还使用了一些分叉的开源库;分叉的原因要么是因为这些库被废弃了,要么是因为我们需要自定义的功能。快速统计显示,大约有 115 个 JavaScript 和原生依赖项。我们希望探索可以移除未使用库的工具。

我们正在通过 TypeScript 添加静态类型,并研究可选链。这些功能可以帮助我们解决我们仍然遇到的几类错误。

  • 数据类型错误
  • 数据未定义,因为对象没有包含我们预期的内容

开源贡献

由于我们非常依赖开源,因此我们的团队致力于回馈社区。Build.com 允许团队开源我们构建的库,并鼓励我们回馈我们使用的库。

我们已经发布并维护了一些 React Native 库

  • react-native-polyfill
  • react-native-simple-store
  • react-native-contact-picker

我们还为许多库做出了贡献,包括:React 和 React Native、react-native-schemes-managerreact-native-swipeablereact-native-galleryreact-native-view-transformerreact-native-navigation

我们的历程

在过去几年里,我们见证了 React Native 及其生态系统的快速发展。早期,React Native 的每个版本似乎都会修复一些错误,但同时也会引入更多错误。例如,远程 JS 调试在 Android 上中断了好几个月。幸运的是,2017 年情况变得更加稳定了。

我们面临的一个重大反复挑战是导航库。长期以来,我们一直在使用 Expo 的 ex-nav 库。它对我们来说运行良好,但最终被弃用了。然而,当时我们正处于功能开发的重头阶段,因此没有时间更换导航库。这意味着我们不得不分叉该库并对其进行修补以支持 React 16 和 iPhone X。最终,我们能够迁移到 react-native-navigation,希望它能够得到持续的支持。

桥接模块

另一个重大挑战是桥接模块。当我们刚开始时,许多关键的桥接模块都缺失。我的一个队友编写了 react-native-contact-picker,因为我们需要在我们的应用中访问 Android 联系人选择器。我们还发现许多桥接模块因 React Native 中的更改而出现故障。例如,React Native v40 中存在一个重大更改,当我们升级应用时,我不得不提交 PR 来修复 3 或 4 个尚未更新的库。

展望未来

随着 React Native 的持续发展,我们对社区的愿望清单包括

  • 稳定并改进导航库
  • 维护对 React Native 生态系统中库的支持
  • 改善向项目添加原生库和桥接模块的体验

React Native 社区的公司和个人一直以来都非常乐意奉献时间和精力来改进我们所有人使用的工具。如果您还没有参与开源,我希望您能考虑改进您使用的一些库的代码或文档。有很多文章可以帮助您入门,这可能比您想象的要容易得多!

为 React Native 构建

·阅读时间:6 分钟
Peter Argany
Facebook 软件工程师

动机

三年前,一个 GitHub 问题被提出,要求 React Native 支持输入附件视图。

在随后的几年里,出现了无数的“+1”、各种变通方法,并且在这个问题上对 RN 没有任何具体的更改 - 直到今天。从 iOS 开始,我们公开了一个 API 用于访问原生输入附件视图,我们很高兴与大家分享我们是如何构建它的。

背景

输入附件视图到底是什么?阅读 Apple 的开发者文档,我们了解到它是一个自定义视图,每当接收者成为第一响应者时,它可以锚定到系统键盘的顶部。任何继承自 UIResponder 的对象都可以将 .inputAccessoryView 属性重新声明为读写属性,并在其中管理自定义视图。响应者基础设施挂载视图,并使其与系统键盘保持同步。像拖动或点击这样的隐藏键盘的手势在框架级别应用于输入附件视图。这使我们能够构建具有交互式键盘隐藏功能的内容,这是 iMessage 和 WhatsApp 等顶级消息应用中的一个重要功能。

将视图锚定到键盘顶部的两种常见用例。第一个是创建键盘工具栏,例如 Facebook 撰写背景选择器。

在这种情况下,键盘聚焦于文本输入字段,而输入附件视图用于提供其他键盘功能。此功能与输入字段的类型相关。在地图应用中,它可能是地址建议,或者在文本编辑器中,它可能是富文本格式化工具。


在这种情况下,拥有 <InputAccessoryView> 的 Objective-C UIResponder 应该很清楚。<TextInput> 已成为第一响应者,在后台它成为 UITextViewUITextField 的实例。

第二个常见场景是粘性文本输入

在这里,文本输入实际上是输入附件视图本身的一部分。这通常用于消息应用中,在其中可以在滚动浏览先前消息的线程时撰写消息。


在此示例中,谁拥有 <InputAccessoryView>?它可以再次是 UITextViewUITextField 吗?文本输入位于输入附件视图内部,这听起来像是一个循环依赖关系。仅解决此问题本身就是 另一篇博文 的内容。剧透:所有者是通用 UIView 子类,我们手动指示它 成为第一响应者

API 设计

现在我们知道了 <InputAccessoryView> 是什么,以及我们如何使用它。下一步是设计一个对这两种用例都有意义的 API,并且可以很好地与现有的 React Native 组件(如 <TextInput>)协同工作。

对于键盘工具栏,我们需要考虑以下几点

  1. 我们希望能够将任何通用 React Native 视图层次结构提升到 <InputAccessoryView> 中。
  2. 我们希望这个通用且分离的视图层次结构能够接受触摸并能够操纵应用程序状态。
  3. 我们希望将 <InputAccessoryView> 链接到特定的 <TextInput>
  4. 我们希望能够在多个文本输入之间共享 <InputAccessoryView>,而无需复制任何代码。

我们可以使用类似于 React portals 的概念来实现 #1。在此设计中,我们将 React Native 视图传送至由响应者基础设施管理的 UIView 层次结构。由于 React Native 视图呈现为 UIViews,因此这实际上非常简单 - 我们只需重写

- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex

并将所有子视图传递到新的 UIView 层次结构。对于 #2,我们为 <InputAccessoryView> 设置了一个新的 RCTTouchHandler。状态更新是通过使用常规事件回调实现的。对于 #3 和 #4,我们使用 nativeID 字段在创建 <TextInput> 组件期间在原生代码中查找附件视图 UIView 层次结构。此函数使用底层原生文本输入的 .inputAccessoryView 属性。这样做有效地将其 ObjC 实现中的 <InputAccessoryView> 链接到 <TextInput>

支持粘性文本输入(场景 2)会增加一些约束。对于此设计,输入附件视图具有文本输入作为子项,因此无法通过 nativeID 进行链接。相反,我们将通用屏幕外 UIView.inputAccessoryView 设置为我们的原生 <InputAccessoryView> 层次结构。通过手动指示此通用 UIView 成为第一响应者,层次结构由响应者基础设施挂载。此概念在前面提到的博文中进行了详细说明。

陷阱

当然,在构建此 API 期间并非一切顺利。以下是我们遇到的几个陷阱,以及我们如何修复它们。

构建此 API 的最初想法包括侦听 NSNotificationCenter 的 UIKeyboardWill(Show/Hide/ChangeFrame) 事件。此模式用于一些开源库,以及 Facebook 应用的某些内部部分。不幸的是,在滑动时,UIKeyboardDidChangeFrame 事件没有及时调用以更新 <InputAccessoryView> 框架。此外,这些事件不会捕获键盘高度的变化。这会产生一类表现如下所示的错误

在 iPhone X 上,文本和表情符号键盘的高度不同。大多数使用键盘事件来操纵文本输入框架的应用程序都必须修复上述错误。我们的解决方案是承诺使用 .inputAccessoryView 属性,这意味着响应者基础设施会处理此类框架更新。


我们遇到的另一个棘手的错误是如何避免 iPhone X 上的 Home 指示器。您可能在想,“Apple 为此专门开发了 safeAreaLayoutGuide,这很简单!”。我们也曾天真地这样认为。第一个问题是原生 <InputAccessoryView> 实现没有窗口可以锚定,直到它即将出现的那一刻。没关系,我们可以重写 -(BOOL)becomeFirstResponder 并强制执行布局约束。遵守这些约束会将附件视图向上移动,但会产生另一个错误:

输入附件视图成功避免了 Home 指示器,但现在不安全区域后面的内容可见。解决方案在于此 radar。我将原生 <InputAccessoryView> 层次结构包装在一个不符合 safeAreaLayoutGuide 约束的容器中。原生容器覆盖不安全区域中的内容,而 <InputAccessoryView> 则保持在安全区域边界内。


使用示例

这是一个构建键盘工具栏按钮以重置 <TextInput> 状态的示例。

class TextInputAccessoryViewExample extends React.Component<
{},
*,
> {
constructor(props) {
super(props);
this.state = {text: 'Placeholder Text'};
}

render() {
const inputAccessoryViewID = 'inputAccessoryView1';
return (
<View>
<TextInput
style={styles.default}
inputAccessoryViewID={inputAccessoryViewID}
onChangeText={text => this.setState({text})}
value={this.state.text}
/>
<InputAccessoryView nativeID={inputAccessoryViewID}>
<View style={{backgroundColor: 'white'}}>
<Button
onPress={() =>
this.setState({text: 'Placeholder Text'})
}
title="Reset Text"
/>
</View>
</InputAccessoryView>
</View>
);
}
}

另一个关于粘性文本输入的示例可以在代码库中找到。

我什么时候可以使用这个功能?

此功能实现的完整提交在这里<InputAccessoryView> 将在即将发布的 v0.55.0 版本中可用。

祝您键盘输入愉快 :)

在 React Native 中使用 AWS

·阅读时间:9 分钟
Richard Threlkeld
AWS Mobile 高级技术产品经理

AWS 在科技行业中以云服务提供商而闻名。这些服务包括计算、存储和数据库技术,以及完全托管的无服务器产品。AWS Mobile 团队一直在与客户和 JavaScript 生态系统成员紧密合作,以使云连接的移动和 Web 应用程序更安全、更具可扩展性,以及更易于开发和部署。我们从一个完整的入门套件开始,但最近还有一些新的开发成果。

这篇博文讨论了一些对 React 和 React Native 开发人员来说有趣的事情。

  • AWS Amplify,一个用于使用云服务的 JavaScript 应用程序的声明式库。
  • AWS AppSync,一个完全托管的 GraphQL 服务,具有离线和实时功能。

AWS Amplify

使用 Create React Native App 和 Expo 等工具可以非常轻松地引导 React Native 应用程序。但是,当您尝试将用例与基础设施服务匹配时,将它们连接到云端可能会很困难。例如,您的 React Native 应用程序可能需要上传照片。这些照片是否应该按用户进行保护?这可能意味着您需要某种注册或登录流程。您是否想要自己的用户目录,或者您是否正在使用社交媒体提供商?也许您的应用程序还需要在用户登录后调用具有自定义业务逻辑的 API。

为了帮助 JavaScript 开发人员解决这些问题,我们发布了一个名为 AWS Amplify 的库。该设计被分解成任务的“类别”,而不是 AWS 特定的实现。例如,如果您希望用户注册、登录,然后上传私有照片,您只需将 AuthStorage 类别引入您的应用程序即可。

import { Auth } from 'aws-amplify';

Auth.signIn(username, password)
.then(user => console.log(user))
.catch(err => console.log(err));

Auth.confirmSignIn(user, code)
.then(data => console.log(data))
.catch(err => console.log(err));

在上面的代码中,您可以看到 Amplify 帮助您完成的一些常见任务的示例,例如使用多因素身份验证 (MFA) 代码通过电子邮件或短信进行身份验证。当前支持的类别有:

  • Auth:提供凭据自动化。开箱即用的实现使用 AWS 凭据进行签名,以及来自Amazon Cognito 的 OIDC JWT 令牌。支持常见的功能,例如 MFA 功能。
  • Analytics:只需一行代码,即可在Amazon Pinpoint 中获取已认证或未认证用户的跟踪信息。您可以根据需要扩展此功能以用于自定义指标或属性。
  • API:以安全的方式提供与 RESTful API 的交互,利用AWS 签名版本 4。API 模块在使用Amazon API Gateway 的无服务器基础设施上非常出色。
  • Storage:简化的命令,用于在Amazon S3 中上传、下载和列出内容。您还可以轻松地将数据分组到每个用户的公共或私有内容中。
  • Caching:跨 Web 应用和 React Native 的 LRU 缓存接口,使用特定于实现的持久性。
  • i18n 和 Logging:提供国际化和本地化功能,以及调试和日志记录功能。

Amplify 的优点之一是它为您的特定编程环境的设计中编码了“最佳实践”。例如,我们在与客户和 React Native 开发人员合作时发现的一件事是,在开发过程中为了快速解决问题而采取的捷径会延续到生产堆栈中。这些捷径可能会影响可扩展性或安全性,并迫使基础设施重新架构和代码重构。

我们如何帮助开发人员避免这种情况的一个示例是使用 AWS Lambda 的无服务器参考架构。这些架构向您展示了在构建后端时将 Amazon API Gateway 和 AWS Lambda 结合使用的最佳实践。此模式编码在 Amplify 的 API 类别中。您可以使用此模式与多个不同的 REST 端点进行交互,并将标头一直传递到您的 Lambda 函数以进行自定义业务逻辑。我们还发布了一个AWS Mobile CLI,用于使用这些功能引导新的或现有的 React Native 项目。要开始使用,只需通过 npm 安装,然后按照配置提示操作即可。

npm install --global awsmobile-cli
awsmobile configure

另一个特定于移动生态系统的编码最佳实践的示例是密码安全性。默认的 Auth 类别实现利用 Amazon Cognito 用户池进行用户注册和登录。此服务实现了安全远程密码协议,作为在身份验证尝试期间保护用户的一种方式。如果您想阅读协议的数学原理,您会注意到在计算密码验证器时,必须使用大素数在原根上生成群。在 React Native 环境中,JIT 已禁用。这使得此类安全操作的 BigInteger 计算性能较差。为了解决这个问题,我们在 Android 和 iOS 中发布了本地桥,您可以在项目中链接这些桥。

npm install --save aws-amplify-react-native
react-native link amazon-cognito-identity-js

我们还很高兴地看到 Expo 团队已将其包含在其最新的 SDK 中,以便您可以在不弹出项目的情况下使用 Amplify。

最后,针对 React Native(和 React)开发,Amplify 包含高阶组件 (HOC),用于轻松封装功能,例如注册和登录到您的应用程序。

import Amplify, { withAuthenticator } from 'aws-amplify-react-native';
import aws_exports from './aws-exports';

Amplify.configure(aws_exports);

class App extends React.Component {
...
}

export default withAuthenticator(App);

底层组件也作为 <Authenticator /> 提供,它可以让您完全控制自定义 UI。它还提供了一些关于管理用户状态的属性,例如他们是否已登录或正在等待 MFA 确认,以及在状态更改时可以触发的回调。

同样,您会发现一些可以用于不同用例的通用 React 组件。您可以根据需要自定义这些组件,例如,在 Storage 模块中显示来自 Amazon S3 的所有私有图像。

<S3Album
level="private"
path={path}
filter={(item) => /jpg/i.test(item.path)}/>

您可以通过 props 控制许多组件功能,如前所述,使用公共或私有存储选项。甚至还有在用户与某些 UI 组件交互时自动收集分析的功能。

return <S3Album track/>

AWS Amplify 倾向于采用约定优于配置的开发风格,使用全局初始化例程或类别级别的初始化。最快的入门方法是使用aws-exports 文件。但是,开发人员也可以使用该库独立于现有资源。

要深入了解其理念并查看完整的演示,请观看来自AWS re:Invent 的视频。

AWS AppSync

在 AWS Amplify 发布后不久,我们还发布了AWS AppSync。这是一种完全托管的 GraphQL 服务,具有离线和实时功能。尽管您可以在不同的客户端编程语言(包括原生 Android 和 iOS)中使用 GraphQL,但它在 React Native 开发人员中非常流行。这是因为数据模型非常适合单向数据流和组件层次结构。

AWS AppSync 使您能够连接到您自己的 AWS 账户中的资源,这意味着您拥有并控制自己的数据。这是通过使用数据源来完成的,并且该服务支持Amazon DynamoDBAmazon ElasticsearchAWS Lambda。这使您能够在一个 GraphQL API 中将功能(例如 NoSQL 和全文搜索)组合成一个模式。这使您能够混合和匹配数据源。AppSync 服务还可以从模式中配置,因此,如果您不熟悉 AWS 服务,您可以编写 GraphQL SDL,点击一个按钮,您就可以自动启动并运行。

AWS AppSync 中的实时功能通过使用众所周知的基于事件的模式的 GraphQL 订阅进行控制。因为 AWS AppSync 中的订阅是使用 GraphQL 指令在模式上控制的,并且模式可以使用任何数据源,这意味着您可以从 Amazon DynamoDB 和 Amazon Elasticsearch Service 的数据库操作或使用 AWS Lambda 的基础设施的其他部分触发通知。

与 AWS Amplify 类似,您可以在使用 AWS AppSync 的 GraphQL API 上使用企业安全功能。该服务允许您快速开始使用 API 密钥。但是,当您迁移到生产环境时,它可以过渡到使用 AWS Identity and Access Management (IAM) 或来自 Amazon Cognito 用户池的 OIDC 令牌。您可以使用类型上的策略在解析器级别控制访问权限。您甚至可以使用逻辑检查来进行细粒度访问控制检查,例如检测用户是否是特定数据库资源的所有者。还有一些功能可以围绕检查组成员资格以执行解析器或单个数据库记录访问。

为了帮助 React Native 开发人员了解这些技术,有一个内置的 GraphQL 示例模式,您可以在 AWS AppSync 控制台主页上启动它。此示例部署了一个 GraphQL 模式,配置了数据库表,并自动为您连接查询、变异和订阅。还有一个功能性的用于 AWS AppSync 的 React Native 示例,它利用了此内置模式(以及一个React 示例),使您能够在几分钟内运行客户端和云组件。

使用AWSAppSyncClient开始非常简单,它可以插入到Apollo Client中。AWSAppSyncClient处理GraphQL API的安全性和签名、离线功能以及订阅握手和协商过程。

import AWSAppSyncClient from "aws-appsync";
import { Rehydrated } from 'aws-appsync-react';
import { AUTH_TYPE } from "aws-appsync/lib/link/auth-link";

const client = new AWSAppSyncClient({
url: awsconfig.graphqlEndpoint,
region: awsconfig.region,
auth: {type: AUTH_TYPE.API_KEY, apiKey: awsconfig.apiKey}
});

AppSync控制台提供了一个可下载的配置文件,其中包含您的GraphQL端点、AWS区域和API密钥。然后,您可以使用React Apollo客户端。

const WithProvider = () => (
<ApolloProvider client={client}>
<Rehydrated>
<App />
</Rehydrated>
</ApolloProvider>
);

此时,您可以使用标准的GraphQL查询。

query ListEvents {
listEvents{
items{
__typename
id
name
where
when
description
comments{
__typename
items{
__typename
eventId
commentId
content
createdAt
}
nextToken
}
}
}
}

上面的示例显示了一个使用AppSync提供的示例应用程序模式的查询。它不仅展示了与DynamoDB的交互,还包括数据的分页(包括加密令牌)以及EventsComments之间的类型关系。由于应用程序使用AWSAppSyncClient配置,因此数据会自动持久化到离线状态,并在设备重新连接时同步。

您可以观看此视频,深入了解其背后的客户端技术以及React Native演示。

反馈

这些库背后的团队渴望了解这些库和服务对您的工作效果。他们还想知道我们还能做些什么,让您更轻松地使用云服务进行React和React Native开发。请通过GitHub联系AWS Mobile团队获取有关AWS AmplifyAWS AppSync的信息。

在 React Native 中实现 Twitter 的应用加载动画

·阅读时间:11分钟
Eli White
Eli White
Meta软件工程师

Twitter的iOS应用程序有一个我非常喜欢的加载动画。

应用程序准备就绪后,Twitter的徽标会愉快地展开,显示应用程序。

我想弄清楚如何使用React Native重新创建此加载动画。


为了理解如何构建它,我首先必须了解加载动画的不同部分。减慢动画速度是查看细微差别的最简单方法。

这里有一些主要部分,我们需要弄清楚如何构建它们。

  1. 缩放小鸟。
  2. 随着小鸟的长大,显示下面的应用程序
  3. 在动画结束时稍微缩小应用程序

我花了相当长的时间才弄清楚如何制作这个动画。

我最初错误地假设蓝色背景和Twitter小鸟是应用程序顶部的一层,并且随着小鸟的长大,它会变得透明,从而显示下面的应用程序。这种方法行不通,因为Twitter小鸟变得透明会显示蓝色层,而不是下面的应用程序!

幸运的是,亲爱的读者,您不必像我一样经历同样的挫折。您可以通过这个不错的教程直接跳到精华部分!


正确的方法

在我们开始编写代码之前,了解如何分解它非常重要。为了帮助您可视化此效果,我在CodePen(嵌入在几个段落中)中重新创建了它,以便您可以交互式地查看不同的图层。

此效果主要有三个图层。第一个是蓝色背景层。即使这似乎出现在应用程序的顶部,它实际上是在后面。

然后我们有一个纯白色的图层。最后,最前面是我们的应用程序。


此动画的主要技巧是使用Twitter徽标作为mask,并掩盖应用程序和白色图层。我不会深入探讨掩盖的细节,有很多资源在线可以帮助您了解它。

在此上下文中,掩盖的基本原理是拥有图像,其中蒙版的不透明像素显示它们正在掩盖的内容,而蒙版的透明像素则隐藏它们正在掩盖的内容。

我们使用Twitter徽标作为蒙版,并使其掩盖两个图层:纯白色图层和应用程序图层。

为了显示应用程序,我们将蒙版放大,直到它大于整个屏幕。

在蒙版放大时,我们淡入应用程序图层的透明度,显示应用程序并隐藏其后面的纯白色图层。为了完成效果,我们让应用程序图层从大于1的比例开始,并在动画结束时缩小到1。然后,我们隐藏非应用程序图层,因为它们将永远不会再被看到。

俗话说,一张图片胜过千言万语。交互式可视化值多少个字?使用“下一步”按钮浏览动画。显示图层可以让您从侧面视角进行查看。网格有助于可视化透明图层。

现在,关于React Native

好了。现在我们知道了要构建什么以及动画的工作原理,我们可以开始编写代码了——您真正来到这里的目的。

这个难题的主要部分是MaskedViewIOS,这是一个React Native核心组件。

import {MaskedViewIOS} from 'react-native';

<MaskedViewIOS maskElement={<Text>Basic Mask</Text>}>
<View style={{backgroundColor: 'blue'}} />
</MaskedViewIOS>;

MaskedViewIOS接受属性maskElementchildren。子元素由maskElement掩盖。请注意,蒙版不需要是图像,它可以是任何任意视图。上面示例的行为将是渲染蓝色视图,但它仅在maskElement中的“Basic Mask”文字所在位置可见。我们只是创建了复杂的蓝色文本。

我们要做的是渲染我们的蓝色层,然后在其顶部使用Twitter徽标渲染我们掩盖的应用程序和白色层。

{
fullScreenBlueLayer;
}
<MaskedViewIOS
style={{flex: 1}}
maskElement={
<View style={styles.centeredFullScreen}>
<Image source={twitterLogo} />
</View>
}>
{fullScreenWhiteLayer}
<View style={{flex: 1}}>
<MyApp />
</View>
</MaskedViewIOS>;

这将为我们提供下面看到的图层。

现在进行动画部分

我们拥有使之工作所需的所有组件,下一步是为它们制作动画。为了使此动画感觉良好,我们将利用React Native的Animated API。

Animated允许我们以声明方式在JavaScript中定义动画。默认情况下,这些动画在JavaScript中运行,并在每一帧告诉本机层要进行哪些更改。即使JavaScript会尝试在每一帧更新动画,但它可能无法足够快地执行此操作,并且会导致出现丢帧(卡顿)。这不是我们想要的!

Animated具有特殊的行为,允许您在没有卡顿的情况下获得动画。Animated有一个名为useNativeDriver的标志,它在动画开始时将您的动画定义从JavaScript发送到本机,允许本机端处理对动画的更新,而无需在每一帧都来回切换到JavaScript。useNativeDriver的缺点是您只能更新特定的一组属性,主要是transformopacity。您无法使用useNativeDriver为诸如背景颜色之类的属性制作动画,至少目前还不行——我们将在以后添加更多内容,当然,您也可以随时为项目所需的属性提交PR,从而使整个社区受益😀。

由于我们希望此动画流畅,因此我们将在此限制范围内工作。要更深入地了解useNativeDriver在幕后如何工作,请查看我们发布它的博文

分解我们的动画

我们的动画有4个组成部分

  1. 放大小鸟,显示应用程序和纯白色图层
  2. 淡入应用程序
  3. 缩小应用程序
  4. 完成后隐藏白色图层和蓝色图层

使用Animated,有两种主要方法可以定义动画。第一种是使用Animated.timing,它允许您准确说明动画将运行多长时间,以及平滑运动的缓动曲线。另一种方法是使用基于物理的api,例如Animated.spring。使用Animated.spring,您可以指定弹簧的摩擦力和张力等参数,并让物理运行动画。

我们希望同时运行多个动画,这些动画彼此密切相关。例如,我们希望应用程序在蒙版处于中间显示状态时开始淡入。由于这些动画密切相关,我们将使用Animated.timing和单个Animated.Value

Animated.Value是本机值的包装器,Animated使用它来了解动画的状态。通常,您只希望为一个完整的动画使用其中一个。大多数使用Animated的组件会将该值存储在状态中。

由于我将此动画视为在完整动画的不同时间点发生的步骤,因此我们将Animated.Value从0开始,表示完成0%,并将我们的值结束为100,表示完成100%。

我们的初始组件状态如下所示。

state = {
loadingProgress: new Animated.Value(0),
};

当我们准备好开始动画时,我们会告诉Animated将此值动画设置为100。

Animated.timing(this.state.loadingProgress, {
toValue: 100,
duration: 1000,
useNativeDriver: true, // This is important!
}).start();

然后,我尝试估算动画的不同部分以及我希望它们在动画的不同阶段具有的值。下表列出了动画的不同部分,以及我认为随着时间的推移,它们在不同点应该具有的值。

Twitter小鸟蒙版应从比例1开始,并在向上放大之前变小。因此,在动画进行到10%时,它应该具有0.8的比例值,然后在最后放大到70。老实说,选择70是相当随意的,它需要足够大才能使小鸟完全显示屏幕,而60不够大😀。关于这部分有趣的一点是,数字越大,看起来增长的速度就越快,因为它必须在相同的时间内到达那里。这个数字需要一些反复试验才能使这个徽标看起来不错。不同尺寸的徽标/设备将需要不同的最终比例,以确保完全显示整个屏幕。

应用程序应该保持不透明一段时间,至少在Twitter徽标变小的时候。根据官方动画,我希望在小鸟放大到中途时开始显示它,并尽快完全显示它。因此,在15%时我们开始显示它,在整个动画进行到30%时,它完全可见。

应用的缩放比例从 1.1 开始,并在动画结束时缩放到其常规比例。

现在,我们来看代码。

我们在上面做的本质上是将动画进度百分比的值映射到各个片段的值。我们使用 .interpolate 通过 Animated 来做到这一点。我们使用基于 this.state.loadingProgress 的插值值创建了 3 个不同的样式对象,每个动画片段一个。

const loadingProgress = this.state.loadingProgress;

const opacityClearToVisible = {
opacity: loadingProgress.interpolate({
inputRange: [0, 15, 30],
outputRange: [0, 0, 1],
extrapolate: 'clamp',
// clamp means when the input is 30-100, output should stay at 1
}),
};

const imageScale = {
transform: [
{
scale: loadingProgress.interpolate({
inputRange: [0, 10, 100],
outputRange: [1, 0.8, 70],
}),
},
],
};

const appScale = {
transform: [
{
scale: loadingProgress.interpolate({
inputRange: [0, 100],
outputRange: [1.1, 1],
}),
},
],
};

现在我们有了这些样式对象,我们可以在渲染文章前面提到的视图片段时使用它们。请注意,只有 Animated.ViewAnimated.TextAnimated.Image 才能使用使用 Animated.Value 的样式对象。

const fullScreenBlueLayer = (
<View style={styles.fullScreenBlueLayer} />
);
const fullScreenWhiteLayer = (
<View style={styles.fullScreenWhiteLayer} />
);

return (
<View style={styles.fullScreen}>
{fullScreenBlueLayer}
<MaskedViewIOS
style={{flex: 1}}
maskElement={
<View style={styles.centeredFullScreen}>
<Animated.Image
style={[styles.maskImageStyle, imageScale]}
source={twitterLogo}
/>
</View>
}>
{fullScreenWhiteLayer}
<Animated.View
style={[opacityClearToVisible, appScale, {flex: 1}]}>
{this.props.children}
</Animated.View>
</MaskedViewIOS>
</View>
);

耶!我们现在已经让动画片段看起来像我们想要的那样了。现在我们只需要清理我们永远不会再看到的蓝色和白色图层。

为了知道何时可以清理它们,我们需要知道动画何时完成。幸运的是,在我们调用 Animated.timing 的地方,.start 接受一个可选的回调函数,该函数在动画完成后运行。

Animated.timing(this.state.loadingProgress, {
toValue: 100,
duration: 1000,
useNativeDriver: true,
}).start(() => {
this.setState({
animationDone: true,
});
});

现在我们在 state 中有一个值来判断我们是否完成了动画,我们可以修改我们的蓝色和白色图层来使用它。

const fullScreenBlueLayer = this.state.animationDone ? null : (
<View style={[styles.fullScreenBlueLayer]} />
);
const fullScreenWhiteLayer = this.state.animationDone ? null : (
<View style={[styles.fullScreenWhiteLayer]} />
);

瞧!我们的动画现在可以工作了,并且在动画完成后我们清理了未使用的图层。我们已经构建了 Twitter 应用加载动画!

但是等等,我的动画不起作用!

不要担心,亲爱的读者。我也讨厌指南只给你代码片段而不给你完整的源代码。

此组件已发布到 npm 并托管在 GitHub 上,地址为 react-native-mask-loader。要在你的手机上试用它,可以 在 Expo 上访问

更多阅读/额外练习

  1. 这本 Gitbook 是一个很好的资源,可以帮助你阅读 React Native 文档后学习更多关于 Animated 的知识。
  2. 实际的 Twitter 动画似乎在结束时加快了蒙版的显示速度。尝试修改加载器以使用不同的缓动函数(或弹簧!)来更好地匹配这种行为。
  3. 蒙版的当前结束缩放比例是硬编码的,在平板电脑上可能无法显示整个应用。根据屏幕尺寸和图像尺寸计算结束缩放比例将是一个很棒的 PR。

React Native 每月 #6

·阅读时间:4 分钟
Tomislav Tenodi
Speck 创始人

React Native 每月会议仍在继续!请务必查看本文底部的说明,了解下一次会议。

Expo

  • 祝贺 Devin AbbottHoussein Djirdeh 预发布“全栈 React Native”书籍!它通过构建几个小型应用来引导你学习 React Native。你可以在购买本书之前在 https://www.fullstackreact.com/react-native/ 上试用这些应用。
  • 发布了 reason-react-native-scripts 的第一个(实验性)版本,以帮助人们轻松试用 ReasonML
  • Expo SDK 24 已 发布!它使用 React Native 0.51 并包含许多新功能和改进:在独立应用中捆绑图像(无需在第一次加载时缓存!)、图像处理 API(裁剪、调整大小、旋转、翻转)、人脸检测 API、新的发布渠道功能(为给定渠道设置活动版本并回滚)、用于跟踪独立应用构建的 Web 仪表板,以及修复了 OpenGL Android 实现和 Android 多任务处理器的长期存在的错误,仅举几例。
  • 从今年 1 月开始,我们将为 React Navigation 分配更多资源。我们坚信,仅使用 React 组件和诸如 Animated 和 react-native-gesture-handler 之类的基本组件构建 React Native 导航是可行且理想的,并且我们对我们计划的一些改进感到非常兴奋。如果你想为社区做出贡献,请查看 react-native-mapsreact-native-svg,这两个项目都可以使用一些帮助!

Infinite Red

Microsoft

  • 已开始进行 请求,以将核心 React Native Windows 桥迁移到 .NET Standard,使其有效地与操作系统无关。希望许多其他 .NET Core 平台可以通过自己的线程模型、JavaScript 运行时和 UIManagers(例如 JavaScriptCore、Xamarin.Mac、Linux Gtk# 和 Samsung Tizen 选项)扩展桥接。

Wix

  • Detox
    • 为了让我们能够扩展端到端测试,我们希望最大程度地减少在 CI 上花费的时间,我们正在研究对 Detox 的并行化支持。
    • 提交了一个 请求,以启用对自定义风格构建的支持,以便更好地支持端到端测试中的模拟。
  • DetoxInstruments
    • DetoxInstruments 的杀手级功能的开发证明是一项非常具有挑战性的任务,在任何给定时间获取 JavaScript 回溯都需要一个自定义的 JSCore 实现来支持 JS 线程挂起。在 Wix 的应用内部测试分析器揭示了关于 JS 线程的有趣见解。
    • 该项目尚不稳定,无法供公众使用,但正在积极开发中,我们希望很快宣布它。
  • React Native Navigation
    • V2 的开发速度已大幅提高,到目前为止,我们只有一位开发人员将其 20% 的时间用于此项目,现在我们有 3 位开发人员全职参与!
  • Android 性能
    • 用最新版本(webkitGTK 项目的最新版本,具有自定义 JIT 配置)替换 RN 中捆绑的旧版 JSCore,使 JS 线程的性能提高了 40%。接下来是编译其 64 位版本。此工作基于 Android 的 JSC 构建脚本。请 在此处 关注其当前状态。

下一次会议

人们一直在讨论将此会议重新用于讨论一个特定主题(例如导航、将 React Native 模块移到单独的存储库中、文档等)。这样我们感觉可以为 React Native 社区做出最好的贡献。这可能会在下一次会议中进行。请随时发布你希望看到的主题。

React Native 每月 #5

·阅读时间:4 分钟
Tomislav Tenodi
Speck 创始人

React Native 每月会议仍在继续!让我们看看我们的团队在做什么。

Callstack

  • 我们一直在研究 React Native CI。最重要的是,我们已从 Travis 迁移到 Circle,使 React Native 拥有一个统一的 CI 管道。
  • 我们组织了 Hacktoberfest - React Native 版本,在那里,我们与参与者一起尝试向开源项目提交了许多请求。
  • 我们继续开发 Haul。上个月,我们发布了两个新版本,包括 webpack 3 支持。我们计划添加 CRNAExpo 支持,以及改进 HMR。我们的路线图在问题跟踪器上公开。如果你想建议改进或提供反馈,请告诉我们!

Expo

  • 发布了 Expo SDK 22(使用 React Native 0.49)并为此更新了 CRNA
    • 包括改进的启动画面 API、基本的 ARKit 支持、“DeviceMotion” API、iOS11 上的 SFAuthenticationSession 支持以及 更多内容。
  • 你的 零食 现在可以有多个 JavaScript 文件,并且你可以通过将图像和其他资源拖放到编辑器中来上传它们。
  • react-navigation 贡献代码以添加对 iPhone X 的支持。
  • 将注意力集中在使用 Expo 构建大型应用时的棘手问题上。例如
    • 对部署到多个环境(登台、生产和任意渠道)提供一流的支持。渠道将支持回滚和为给定渠道设置活动版本。如果你想成为早期测试人员,请告诉我们,@expo_io
    • 我们还在努力改进我们的独立应用构建基础架构,并在保持通过空中更新资源能力的同时,添加对在独立应用构建中捆绑图像和其他非代码资源的支持。

Facebook

  • 更好的 RTL 支持
    • 我们正在引入许多方向感知样式。
      • 位置
        • (left|right) → (start|end)
      • 边距
        • margin(Left|Right) → margin(Start|End)
      • 填充
        • padding(Left|Right) → padding(Start|End)
      • 边框
        • borderTop(Left|Right)Radius → borderTop(Start|End)Radius
        • borderBottom(Left|Right)Radius → borderBottom(Start|End)Radius
        • border(Left|Right)Width → border(Start|End)Width
        • border(Left|Right)Color → border(Start|End)Color
    • 在 RTL 布局下,“left” 和 “right” 的含义在 position、margin、padding 和 border 样式中被交换了。在几个月内,我们将移除此行为,并使“left”始终表示“左侧”,“right”始终表示“右侧”。这些破坏性更改隐藏在一个 flag 后面。在您的 React Native 组件中使用 I18nManager.swapLeftAndRightInRTL(false) 来选择加入这些更改。
  • 正在使用 Flow 为我们的内部原生模块编写类型,并使用这些类型在 Java 中生成接口,以及在 ObjC 中生成原生实现必须实现的协议。我们希望此代码生成工具最早明年开源。

Infinite Red

  • 用于帮助 React Native 和其他项目的新的开源工具。更多信息请访问 此处
  • 正在重新设计 Ignite 以发布新的样板文件(代号:Bowser)。

Shoutem

  • 改进 Shoutem 的开发流程。我们希望简化从创建应用到第一个自定义屏幕的过程,并使其变得非常简单,从而降低新 React Native 开发者的入门门槛。准备了一些研讨会来测试新功能。我们还改进了 Shoutem CLI 以支持新的流程。
  • Shoutem UI 进行了几个组件改进和错误修复。我们还检查了与最新 React Native 版本的兼容性。
  • Shoutem 平台进行了一些值得注意的更新,新的集成作为 开源扩展项目的一部分提供。我们非常高兴看到其他开发者积极参与 Shoutem 扩展的开发。我们积极联系他们,并为他们的扩展提供建议和指导。

下次会议

下次会议定于 2017 年 12 月 6 日星期三举行。如果您对如何改进会议成果有任何建议,请随时在 Twitter 上联系我。

React Native 每月 #4

·阅读时间:3 分钟
Mike Grabowski
Mike Grabowski
Callstack 首席技术官兼联合创始人

React Native 每月会议继续!以下是每个团队的会议纪要。

Callstack

  • React Native EU 已经结束。来自 33 个国家的 300 多名参与者访问了弗罗茨瓦夫。可以在 YouTube 上找到演讲视频。
  • 会议结束后,我们正在慢慢恢复到开源计划中。值得一提的是,我们正在开发 react-native-opentok 的下一个版本,该版本修复了大多数现有问题。

GeekyAnts

尝试通过以下方式降低拥抱 React Native 的开发者的入门门槛

  • React Native EU 上宣布了 BuilderX.io。BuilderX 是一款设计工具,可直接使用 JavaScript 文件(目前仅支持 React Native)生成美观、可读且可编辑的代码。
  • 推出了 ReactNativeSeed.com,它为您的下一个 React Native 项目提供了一组样板文件。它提供了各种选项,包括用于数据类型的 TypeScript & Flow、用于状态管理的 MobX、Redux 和 mobx-state-tree,以及 CRNA 和纯 React-Native 作为技术栈。

Expo

  • 即将发布 SDK 21,它增加了对 react-native 0.48.3 的支持,以及 Expo SDK 中的一系列错误修复/可靠性改进/新功能,包括视频录制、新的启动屏幕 API、对 react-native-gesture-handler 的支持以及改进的错误处理。
  • 关于 react-native-gesture-handlerKrzysztof Magiera(来自 Software Mansion)继续推动这项工作,我们一直在帮助他进行测试并资助他部分开发时间。将其集成到 SDK21 的 Expo 中,将使人们能够轻松地在 Snack 中使用它,因此我们很高兴看到人们会想出什么创意。
  • 关于改进的错误日志记录/处理 - 请参阅 Expo 内部 PR 的这段信息,了解有关日志记录的详细信息(特别是“问题 2”),以及 此提交,了解处理导入 npm 标准库模块失败尝试的更改。可以通过这种方式在 React Native 中改进错误消息,我们将在后续的 upstream PR 中进行改进。社区参与进来将非常棒。
  • native.directory 正在不断发展,您可以从 GitHub 仓库 中添加您的项目。
  • 参加北美的黑客马拉松,包括 PennAppsHack The NorthHackMIT,以及即将到来的 MHacks

Facebook

  • 正在改进 Android 上的 <Text><TextInput> 组件。(<TextInput> 的原生自动增长;嵌套深度较深的 <Text> 组件布局问题;更好的代码结构;性能优化)。
  • 我们仍在寻找额外的贡献者,他们愿意帮助分类问题和拉取请求。

Microsoft

  • 发布了 CodePush 的代码签名功能。React Native 开发人员现在能够在 CodePush 中签名他们的应用程序包。公告可以在这里找到 此处
  • 正在完成 CodePush 与 Mobile Center 的集成。同时也在考虑测试/崩溃集成。

下次会议

下次会议定于 2017 年 10 月 10 日星期三举行。由于这仅仅是我们的第四次会议,我们想知道这些会议纪要如何使 React Native 社区受益。如果您对如何改进会议成果有任何建议,请随时在 Twitter 上联系我。

React Native 每月 #3

·阅读时间:5 分钟
Mike Grabowski
Mike Grabowski
Callstack 首席技术官兼联合创始人

React Native 每月会议继续!本月的会议时间较短,因为我们的大多数团队都很忙于发布产品。下个月,我们将参加在波兰弗罗茨瓦夫举行的 React Native EU 大会。请务必获取门票,我们期待在那里与您见面!同时,让我们看看我们的团队在做什么。

团队

在第三次会议上,有 5 个团队加入了我们。

会议纪要

以下是每个团队的会议纪要。

Callstack

  • 最近开源了 react-native-material-palette。它从图像中提取突出的颜色,以帮助您创建视觉吸引力的应用。目前仅支持 Android,但我们正在考虑将来添加对 iOS 的支持。
  • 我们在 haul 中实现了 HMR 支持,以及其他一些很酷的功能!请查看最新的版本。
  • React Native EU 2017 即将到来!下个月的一切都围绕着 React Native 和波兰!请务必在此处获取最后几张门票 此处

Expo

  • 发布了对在 Snack 上安装 npm 包的支持。适用通常的 Expo 限制 - 包不能依赖于尚未包含在 Expo 中的自定义原生 API。我们还在努力支持 Snack 中的多个文件和上传资产。 Satyajit 将在 React Native Europe 上谈论 Snack。
  • 发布了 SDK20,其中包含相机、支付、安全存储、磁力计、暂停/恢复 fs 下载以及改进的启动/加载屏幕。
  • 继续与 Krzysztof 合作开发 react-native-gesture-handler。请尝试一下,重构一些您之前使用 PanResponder 或原生手势识别器构建的手势,并告诉我们您遇到的问题。
  • 正在试验 JSC 调试协议,并在 Canny 上处理大量功能请求。

Facebook

  • 上个月我们讨论了 GitHub 问题跟踪器的管理,以及我们将尝试进行改进以解决项目的可维护性。
  • 目前,未解决问题的数量稳定在 600 左右,并且似乎在一段时间内将保持这个状态。在上个月,由于缺乏活动(定义为在过去 60 天内没有评论),我们关闭了 690 个问题。在这 690 个问题中,有 58 个由于各种原因被重新打开(维护人员承诺提供修复程序,或者贡献者提出了充分的理由来保持问题处于打开状态)。
  • 我们计划在可预见的将来继续自动关闭陈旧的问题。我们希望能够处理跟踪器中打开的每个有影响力的问题,但我们还没有达到那个状态。我们需要维护人员提供尽可能多的帮助来分类问题,并确保我们不会错过导致回归或引入重大更改的问题,尤其是那些影响新创建项目的问题。有兴趣提供帮助的人可以使用 Facebook GitHub 机器人来分类问题和拉取请求。新的维护人员指南包含有关分类和使用 GitHub 机器人的更多信息。请将自己添加到 问题工作组 中,并鼓励其他活跃的社区成员也这样做!

Microsoft

  • 新的 Skype 应用是在 React Native 之上构建的,以便尽可能地在平台之间共享代码。基于 React Native 的 Skype 应用目前已在 Android 和 iOS 应用商店中提供。
  • 在使用 React Native 构建 Skype 应用时,我们向 React Native 发送拉取请求以解决我们遇到的错误和缺少的功能。到目前为止,我们已经获得了大约 70 个拉取请求已合并
  • React Native 让我们能够使用同一个代码库为 Android 和 iOS 版 Skype 应用提供支持。我们也希望使用该代码库为 Skype 网页应用提供支持。为了帮助我们实现这一目标,我们在 React/React Native 之上构建并开源了一个轻量级层,称为ReactXP。ReactXP 提供了一组跨平台组件,在目标平台为 iOS/Android 时映射到 React Native,在目标平台为网页时映射到 react-dom。ReactXP 的目标与另一个名为 React Native for Web 的开源库类似。在ReactXP 常见问题解答中简要描述了这些库方法之间的差异。

Shoutem

  • 我们正在继续努力改进和简化使用Shoutem构建应用时的开发者体验。
  • 开始将所有应用迁移到 react-navigation,但我们决定推迟到发布更稳定的版本,或其中一个原生导航解决方案变得稳定后再进行。
  • 将我们所有的扩展和大多数开源库(动画主题UI)更新到 React Native 0.47.1。

下次会议

下一场会议定于 2017 年 9 月 13 日星期三举行。由于这只是我们的第三次会议,我们想知道这些记录如何惠及 React Native 社区。如果您有任何关于如何改进会议成果的建议,请随时在Twitter 上联系我。