跳至主内容

发布 0.56 版本

· 1 分钟阅读
Lorenzo Sciandra
核心维护者 & Drivetribe 的 React Native 开发者
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

期待已久的 React Native 0.56 版本现已发布 🎉。本篇博客将重点介绍此版本中的部分变更内容。我们同时借此机会说明自三月份以来团队的工作重点。

重大变更的困境,或者说,"何时发布?"

贡献者指南详细说明了所有 React Native 变更所需经历的集成流程。该项目由众多不同的工具构成,需要持续协调与支持才能确保所有环节正常运行。再加上为项目积极贡献的活跃开源社区,您就能感受到整个工程令人难以置信的规模。

鉴于 React Native 的广泛采用,重大变更必须极其谨慎地实施,而实际流程并不如预期顺利。核心团队决定跳过四月和五月的版本发布,以便集中精力集成和测试一系列重大变更。我们全程使用专门的社区沟通渠道,确保 2018 年 6 月发布的 0.56.0 版本能尽可能顺利地被耐心等待稳定版的开发者采用。

0.56.0 完美吗?不完美,就像所有软件一样:但我们在"等待更高稳定性"与"测试已取得积极成果可以推进"之间找到了平衡点,因此决定正式发布。此外,我们已知悉最终 0.56.0 版本中仍存在若干待解决问题。大多数开发者升级到 0.56.0 应该不会遇到问题。若您因上述问题受阻,我们期待在讨论区见到您的参与,并希望与您共同寻找解决方案。

您可将 0.56.0 视为构建更稳定框架的重要基石:可能需要一至两周的广泛采用才能解决所有边缘情况,但这将为 2018 年 7 月的 0.57.0 版本奠定更坚实的基础。

在本章节结尾,我们要特别感谢所有 67 位贡献者完成的 818 次提交 (!),这些工作将帮助您的应用更臻完善 👏。

那么,闲话少说...

重大变更

Babel 7

众所周知,让我们能够使用 JavaScript 最新强大功能的转译工具 Babel 即将升级到 v7 版本。由于新版本带来诸多重要改进,我们认为当前正是升级良机,这将使 Metro 能够充分利用其优化特性

若您在升级过程中遇到问题,请参阅相关文档章节

Android 支持的现代化

在 Android 方面,我们更新了大量周边工具链。现已升级至 Gradle 3.5Android SDK 26Fresco 1.9.0 和 OkHttp 3.10.0,甚至将 NDK API 目标版本提升至 API 16。这些变更应能平稳过渡并带来更快的构建速度。更重要的是,这将帮助开发者满足下月生效的 Google Play 商店新要求

我们要特别感谢 Dulmandakh 为此提交的多项 PR,正是这些贡献让此次升级成为可能 👏。

这方面仍需更多改进措施,您可通过专门议题(以及关于 JSC 的单独议题)参与未来 Android 支持更新的规划讨论。

全新的 Node、Xcode、React 和 Flow

Node 8 现已成为 React Native 的标准配置。其实此前已在测试中推进,但随着 Node 6 进入维护模式,我们全面转向了 Node 8。React 也同步更新至 16.4 版本,带来了大量修复更新。

我们将停止支持 iOS 8,iOS 9 成为可支持的最低版本。所有能运行 iOS 8 的设备均可升级至 iOS 9,因此这不会造成实质影响。此项变更让我们移除了专为 iOS 8 老旧设备设计的兼容代码。

持续集成工具链已更新至 Xcode 9.4,确保所有 iOS 测试都在 Apple 提供的最新开发者工具环境中运行。

我们升级至 Flow 0.75 以采用广受开发者好评的新错误格式。同时为更多组件添加了类型定义。若您尚未在项目中实施静态类型检查,建议尝试使用 Flow 在编码时而非运行时发现问题。

以及更多改进...

例如,YellowBox 被全新实现方案取代,显著提升了调试体验。

完整发布说明请查阅此处变更日志。升级前请务必参考升级指南以避免版本迁移问题。


最后提醒:从本周开始,React Native 核心团队将恢复举行月度会议。我们将确保及时同步会议讨论内容,并将您的反馈纳入未来会议考量。

祝大家编码愉快!

LorenzoRyan 及全体 React Native 核心团队成员

附注: 我们再次提醒大家,由于 React Native 仍处于快速迭代阶段(0.x 版本),升级时可能会遇到崩溃或功能异常。请在 issue 讨论和提交 PR 时保持友善互助,并始终遵守我们推行的 CoC 行为准则——请记住,屏幕对面永远是一个真实的人。

React Native 2018 年现状

· 1 分钟阅读
Sophie Alpert
Facebook React 工程经理
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

距离我们上次发布 React Native 的现状更新已有一段时间。

在 Facebook,我们比以往任何时候都更广泛地在重要项目中使用 React Native。其中最受欢迎的产品是 Marketplace——这是我们应用中每月被 8 亿用户使用的顶级标签页之一。自 2015 年创建以来,Marketplace 完全采用 React Native 构建,包含遍布应用不同部分的数百个全屏视图。

我们也在应用的许多新模块中使用 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 状态更新转换为 document.createElement(attrs).appendChild() 等 DOM API 的命令式可变调用,React Native 被设计为返回列出待执行变更的单一 JSON 消息,例如 [["createView", attrs], ["manageChildren", ...]]。我们设计的整个系统从不依赖同步响应,并确保列表中所有内容都能完全序列化为 JSON 并还原。这样做是为了获得灵活性:基于此架构,我们得以构建诸如Chrome 调试等工具,该工具通过 WebSocket 连接异步运行所有 JavaScript 代码。

过去五年我们发现,这些初始原则使得某些功能的构建更加困难。异步桥接意味着无法将 JavaScript 逻辑直接集成到许多需要同步响应的原生 API 中。批处理桥接会对原生调用进行排队,导致 React Native 应用更难调用原生实现的函数。而可序列化桥接则意味着不必要的内存复制,而非直接在两个环境间共享内存。对于完全采用 React Native 构建的应用,这些限制通常可以接受。但对于 React Native 与现有应用代码需复杂集成的场景,这些限制令人沮丧。

我们正在进行 React Native 的大规模架构重构,以使框架更灵活,并与 JavaScript/原生混合应用中的原生基础设施更好集成。 通过该项目,我们将应用过去五年积累的经验,逐步将架构升级至更现代化的形态。我们正在重写 React Native 的许多内部实现,但大部分变更都在底层:现有 React Native 应用将继续运行,几乎不需要修改。

为了让 React Native 更轻量级并更好地融入现有原生应用,这次架构重构包含三大内部改进。首先,我们正在改变线程模型。用户界面更新不再需要在三个不同线程上执行工作,新架构允许在任何线程上同步调用 JavaScript 来处理高优先级更新,同时仍将低优先级任务移出主线程以保持响应能力。其次,我们将异步渲染能力整合到 React Native 中,以支持多级渲染优先级并简化异步数据处理。最后,我们正在简化桥接机制,使其更快速轻量:原生代码与 JavaScript 之间的直接调用将更高效,并便于构建跨语言堆栈追踪等调试工具。

这些改进完成后,更深入的集成将成为可能。当前若想整合原生导航/手势处理或 UICollectionView、RecyclerView 等原生组件,必须采用复杂技巧。线程模型改造后,构建此类功能将变得直接高效。

我们将在今年晚些时候这项工作接近完成时公布更多细节。

社区生态

除 Facebook 内部社区外,我们欣喜地看到外部 React Native 用户和贡献者生态蓬勃发展。我们期待通过优化开发者体验和降低贡献门槛,为社区提供更完善的支持。

正如架构改进能提升 React Native 与其他原生设施的协同能力,我们也致力于精简 JavaScript 侧架构:包括支持可替换的虚拟机与打包工具,使其更契合 JavaScript 生态系统。我们理解重大变更的更新节奏可能带来适配压力,因此将探索减少大版本更新的方案。同时针对启动优化等尚未系统文档化的专业领域,我们将补充更详实的指南。这些改进将在未来一年逐步落地。

只要您在使用 React Native,就是社区的重要成员——请继续告诉我们如何为您打造更出色的开发体验。

虽然 React Native 只是移动开发者工具箱中的选项之一,但我们坚信其价值——去年 500+ 贡献者提交的 2500 多次代码更新,正推动它日臻完善。

在 React Native 中使用 TypeScript

· 1 分钟阅读
Ash Furrow
Artsy 软件工程师
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

JavaScript!我们都爱它。但有些人也钟爱类型系统。幸运的是,有多种方案可以为 JavaScript 增加强类型支持。我最喜欢的是 TypeScript,不过 React Native 默认支持 Flow。选择哪种方案完全取决于个人偏好,它们各自有不同的方式为 JavaScript 添加类型的魔力。今天,我们将探讨如何在 React Native 应用中使用 TypeScript。

本文参考了微软的 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-jestdevDependencies

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 应用

· 1 分钟阅读
Garrett McCullough
高级移动开发工程师
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

Build.com总部位于加利福尼亚州奇科市,是家装领域规模最大的在线零售商之一。团队18年来始终专注于网页业务,并于2015年开始规划移动应用。由于团队规模有限且原生开发经验不足,同时构建Android和iOS双平台应用并不现实。因此我们决定冒险尝试当时全新的React Native框架——2015年8月12日我们首次提交代码,使用的正是React Native v0.8.0!2016年10月15日,应用正式登陆两大应用商店。过去两年间,我们持续升级并扩展应用功能,目前运行的是React Native v0.53.0版本。

您可通过https://www.build.com/app体验这款应用。

功能亮点

我们的应用功能完备,包含电商应用应有的所有特性:产品展示、搜索排序、复杂产品配置、收藏夹等。支持标准信用卡支付,同时为iOS用户提供PayPal和Apple Pay选项。

以下特色功能可能超出您的预期:

  1. 约40款产品提供90种表面处理的3D模型展示

  2. 增强现实(AR)功能让用户以98%的尺寸精度预览灯具/水龙头在家中的实际效果。Build.com的React Native应用因此入选苹果应用商店AR购物推荐!现已在Android/iOS双平台开放AR功能!

  3. 协作式项目管理功能,支持用户为项目不同阶段创建采购清单并协同筛选商品

我们正在开发多项激动人心的新功能以持续优化应用体验,包括AR沉浸式购物的下一阶段升级。

开发工作流

Build.com允许每位开发者选用最适合自己的工具:

  • 集成开发环境包括Atom、IntelliJ、VS Code、Sublime、Eclipse等

  • 单元测试方面,开发者需为新组件编写Jest单元测试,同时正通过jest-coverage-ratchet提升旧模块的测试覆盖率

  • 使用Jenkins构建测试版和候选发布版,该流程运行良好但生成版本说明等文档仍需大量工作

  • 集成测试由跨桌面/移动/网页平台的共享测试池完成,自动化工程师正基于Java+Appium构建自动化测试套件

  • 工作流还包括精细的eslint配置、强化测试所需属性的自定义规则,以及拦截问题代码的预提交钩子

应用依赖库

Build.com应用依赖多个主流开源库:Redux、Moment、Numeral、Enzyme及众多React Native桥接模块。同时使用了若干分叉版本的开源库——或因原项目停止维护,或因需定制功能。粗略统计约含115个JavaScript与原生依赖项,未来计划探索移除未使用库的工具。

我们正通过TypeScript引入静态类型检查,并探索可选链式调用(optional chaining)特性。这些功能有助于解决以下两类常见问题:

  • 数据类型错误

  • 因对象属性缺失导致的未定义数据

开源贡献

由于我们深度依赖开源技术,团队致力于回馈社区。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 版本在修复部分问题的同时总会引入新问题。例如 Android 平台的远程 JS 调试功能曾失效数月之久。值得欣慰的是,2017 年后平台稳定性大幅提升。

导航库

导航库的选择始终是我们面临的主要挑战。我们曾长期使用 Expo 的 ex-nav 库,效果良好但最终停止维护。由于当时正处于密集功能开发阶段,我们不得不分叉该库并自行添加对 React 16 和 iPhone X 的支持。最终我们成功迁移到 react-native-navigation,期望它能获得长期维护。

桥接模块

另一大挑战来自桥接模块。项目初期许多关键桥接功能缺失,例如团队成员开发了 react-native-contact-picker 来实现 Android 通讯录选择功能。同时 React Native 的版本升级常导致桥接模块失效,例如 v40 升级时我们不得不主动提交 PR 修复了 3-4 个未更新的库。

未来展望

随着 React Native 持续发展,我们对社区有以下期待:

  • 增强导航库的稳定性与功能

  • 保持 React Native 生态库的兼容维护

  • 优化原生库和桥接模块的集成体验

React Native 社区中的企业和个人始终积极贡献时间精力改进共享工具。若您尚未参与开源贡献,不妨尝试改进所用库的代码或文档。相关入门指南非常丰富,实践难度可能远低于您的预期!

为 React Native 构建 <InputAccessoryView>

· 1 分钟阅读
Peter Argany
Facebook 软件工程师
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

背景动机

三年前,有人提交了一个 GitHub issue,要求 React Native 支持 input accessory view。

在随后的几年里,这个问题收到了无数的 "+1" 和各种变通方案,但 RN 本身却没有任何实质改变——直到今天。我们从 iOS 平台开始,公开了访问原生 input accessory view 的接口,并很高兴分享我们的实现方案。

背景知识

究竟什么是 input accessory view?阅读 Apple 开发者文档可知,它是一个自定义视图,当接收者成为第一响应者时,可以固定在系统键盘顶部。任何继承自 UIResponder 的对象都可重新声明 .inputAccessoryView 属性,并在此管理自定义视图。响应者基础架构会挂载该视图,并使其与系统键盘保持同步。用于关闭键盘的手势(如拖动或点击)会在框架层应用于 input accessory view。这让我们能实现交互式键盘收起功能——这是 iMessage 和 WhatsApp 等顶级通讯应用的核心特性。

将视图固定在键盘顶部有两种常见场景:第一种是创建键盘工具栏,例如 Facebook 发帖编辑器的背景选择器。

在此场景中,键盘聚焦于文本输入框,input accessory view 用于提供额外的键盘功能。这些功能与输入框类型相关:地图应用中可能是地址建议,文本编辑器中则可能是富文本格式工具。


在此场景中,拥有 <InputAccessoryView> 的 Objective-C UIResponder 很明确:当 <TextInput> 成为第一响应者时,底层会变成 UITextViewUITextField 实例。

第二种常见场景是粘性文本输入框:

此时文本输入框本身是 input accessory view 的组成部分。这常见于消息应用,用户可在滚动查看历史消息的同时编写新消息。


此例中谁拥有 <InputAccessoryView>?还能是 UITextViewUITextField 吗?文本输入框竟_位于_ input accessory view 内部,这形成了循环依赖。单独解决这个问题就值得另写一篇博客。剧透:拥有者是一个通用的 UIView 子类,我们会手动触发它的 becomeFirstResponder 方法。

接口设计

现在我们知道 <InputAccessoryView> 是什么以及如何使用它。下一步是设计一个同时满足两种场景的接口,并与现有 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,我们在创建 <TextInput> 组件时,使用 nativeID 字段在原生代码中定位辅助视图的 UIView 层次结构。该函数利用底层原生文本输入的 .inputAccessoryView 属性,从而在 ObjC 实现中有效地将 <InputAccessoryView><TextInput> 关联起来。

支持粘性文本输入(场景二)带来额外约束。这种设计中输入辅助视图本身包含文本输入子元素,因此无法通过 nativeID 关联。我们改为将通用离屏 UIView.inputAccessoryView 属性设置为我们原生的 <InputAccessoryView> 层次结构。通过手动使该通用 UIView 成为第一响应者,响应者基础设施便会挂载该层次结构。此概念在前述博客文章中有详细阐述。

陷阱与解决方案

当然,在构建此 API 的过程中并非一帆风顺。以下是我们遇到的一些陷阱及其解决方案。

最初的构建方案涉及监听 NSNotificationCenter 的 UIKeyboardWill(Show/Hide/ChangeFrame) 事件。该模式在某些开源库和 Facebook 应用内部模块中使用。遗憾的是,在滑动操作时,UIKeyboardDidChangeFrame 事件未能及时触发以更新 <InputAccessoryView> 的帧位置。此外,键盘高度变化也不会被这些事件捕获,导致如下缺陷:

在 iPhone X 上,文本键盘与表情键盘高度不同。依赖键盘事件操控文本输入框的应用都需修复此缺陷。我们的解决方案是坚持使用 .inputAccessoryView 属性,这意味着响应者基础设施会处理此类帧更新。


另一个棘手问题是避免与 iPhone X 的 Home 指示条重叠。您可能认为:"苹果为此专门开发了 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

· 1 分钟阅读
Richard Threlkeld
AWS Mobile 高级技术产品经理
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

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:通过 AWS 签名版本 4 安全地与 RESTful API 交互。该模块在配合 Amazon API Gateway 的无服务器架构中表现优异。

  • Storage:简化了 Amazon S3 内容的上传、下载和列表操作。还可轻松按用户分组公开或私有数据。

  • Caching:跨 Web 应用和 React Native 的 LRU 缓存接口,采用特定实现的持久化方案。

  • i18n and 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用户池处理用户注册和登录。该服务采用安全远程密码协议(SRP)来保护用户认证过程。如果您有兴趣研究该协议的数学原理,会注意到在原始根上计算密码验证器生成群组时必须使用大质数。在React Native环境中JIT被禁用,导致此类安全计算中的BigInteger运算性能较低。为此我们发布了Android和iOS原生桥接模块,可直接集成到项目中:

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

令人振奋的是,Expo团队已将此功能纳入其最新SDK,您现在无需eject项目即可使用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 订阅模式实现。由于订阅功能使用 GraphQL 指令在架构层进行控制,而架构可使用任意数据源,这意味着您可以通过 Amazon DynamoDB 和 Amazon Elasticsearch Service 的数据库操作触发通知,或通过 AWS Lambda 从基础设施其他部分触发。

与 AWS Amplify 类似,您可以在 AWS AppSync 的 GraphQL API 中使用企业级安全功能。该服务支持通过 API 密钥快速上手,但在生产环境中可无缝切换到 AWS IAM 或 Amazon Cognito 用户池的 OIDC 令牌。您可以在解析器层级通过类型策略控制访问权限,甚至能在运行时执行细粒度访问控制检查(例如验证用户是否为特定数据库资源所有者),还支持通过群组成员检查来执行解析器或数据库记录访问。

为帮助 React Native 开发者快速上手,AWS AppSync 控制台主页提供内置 GraphQL 示例架构。该示例会自动部署 GraphQL 架构、配置数据库表并连接查询/变更/订阅操作。我们还提供了可直接运行的 React Native 示例项目(以及 React 版本),帮助您在几分钟内同时启动客户端和云端组件。

使用 AWSAppSyncClient 非常简单,它直接集成 Apollo ClientAWSAppSyncClient 会自动处理 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 应用加载动画

· 1 分钟阅读
Eli White
Eli White
Software Engineer @ Meta
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

Twitter iOS 应用的加载动画让我非常喜欢。

当应用准备就绪时,Twitter 小鸟标志会优雅地展开,显露出应用界面。

我想探索如何在 React Native 中重现这个加载动画。


要理解构建方法,首先需要拆解加载动画的各个组成部分。观察细节最简单的方法是放慢速度观看。

这个动画包含几个关键部分需要我们实现:

  1. 小鸟标志的缩放

  2. 小鸟扩展时显示下方应用界面

  3. 最后阶段轻微缩小应用界面

我花了相当长时间才搞明白如何制作这个动画。

最初我有个错误假设:认为蓝色背景和小鸟是覆盖在应用上方的图层,随着小鸟放大逐渐变得透明从而显示下方应用。这种方法行不通,因为小鸟变透明后露出的会是蓝色背景,而不是应用界面!

幸运的是,亲爱的读者,您不必经历同样的挫折。本教程将带您直达关键实现部分!


正确的实现方式

在编写代码前,理解如何拆解这个效果很重要。为帮助可视化,我在 CodePen 上重建了这个效果(嵌入在下方段落中),您可以交互式查看不同图层。

这个效果包含三个主要图层:最底层是蓝色背景层。虽然它看起来像是在应用上方,实际位于最后方。

中间是纯白色图层。最前面则是我们的应用层。


这个动画的核心技巧是将 Twitter 标志作为 mask(遮罩),同时遮盖应用层和白色层。关于遮罩细节我不做深入探讨,网上有大量相关资源

在此背景下,遮罩的基本原理是:遮罩图像的不透明像素会显示被遮盖内容,而透明像素则隐藏被遮盖内容。

我们将 Twitter 标志作为遮罩,用它遮盖两个图层:纯白色层和应用层。

通过将遮罩放大到超过整个屏幕的尺寸来显示应用界面。

在遮罩放大过程中,我们逐渐增加应用层的不透明度,从而显示应用界面并隐藏后方的纯白层。最后阶段,我们将应用层从大于1的初始比例缩小至1。动画结束后隐藏非应用图层。

常言道一图胜千言。那么交互式可视化值多少词呢?点击"Next Step"按钮逐步查看动画效果。图层展示提供了侧视角度,网格线帮助可视化透明图层。

现在进入 React Native 实现

好的。既然我们理解了构建目标和动画原理,现在可以进入代码环节——这才是您阅读的真正目的。

实现的关键组件是 MaskedViewIOS,这是 React Native 的核心组件。

import {MaskedViewIOS} from 'react-native';

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

MaskedViewIOS 接收 maskElementchildren 两个 props。子元素会被 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 提供了特殊机制避免卡顿:通过设置 useNativeDriver 标志,可以在动画开始时将定义从 JavaScript 发送到原生层,让原生端独立处理动画更新,无需每帧与 JavaScript 通信。useNativeDriver 的限制是只能修改特定属性(主要是 transformopacity),目前无法用 useNativeDriver 实现背景色等属性的动画。当然,未来我们会扩展支持范围,也欢迎提交 PR 来增加项目所需属性,让整个社区受益 😀。

为确保动画流畅,我们将在这些约束条件下工作。深入了解 useNativeDriver 底层原理,请参阅相关博客文章

分解动画步骤

我们的动画包含 4 个关键部分:

  1. 放大小鸟图标,逐渐显示应用和纯白层

  2. 淡入应用界面

  3. 轻微缩小应用界面

  4. 完成后隐藏白色层和蓝色层

Animated 提供两种主要动画定义方式:Animated.timing 可精确控制时长和缓动曲线;Animated.spring 则基于物理模型。使用 Animated.spring 时,你可以通过摩擦力和张力参数实现弹性效果。

由于多个动画需要同步进行(例如在遮罩展开中途开始淡入应用),且它们彼此关联,我们将使用 Animated.timing 配合单一 Animated.Value 实现。

Animated.Value 是封装动画状态值的容器。通常整个动画只需一个该值,大多数组件会将其存储在 state 中。

我们将动画视为随时间推进的连续过程:设置 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显然不够😀。有趣的是,这个最终值越大,缩放速度看起来就越快,因为必须在相同时间内达到更大倍数。经过反复调试才找到适合当前Logo的数值。不同尺寸的Logo/设备需要不同的最终缩放值,以确保完整显示屏幕内容。

应用界面需要保持不透明状态一段时间,至少要覆盖Logo缩小阶段。根据官方动画效果,我计划在小鸟放大到一半时开始显示应用界面,并快速完成过渡。因此在动画进度15%时开始显现,到30%时实现完全可见。

应用界面初始缩放值为1.1,随动画推进逐渐缩小至正常尺寸。

代码实现

上述过程本质是将整体动画进度映射到各独立元素的参数值。我们通过Animated的.interpolate方法实现这种映射。基于this.state.loadingProgress的插值计算,我们为动画的三个组成部分分别创建了对应的样式对象。

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是学习Animated的绝佳资源,尤其适合已掌握React Native基础文档的开发者

  2. 实际Twitter动画在最后阶段会加速遮罩展开过程。尝试修改加载器,使用不同的缓动函数(或弹性动画)来模拟这种效果

  3. 当前遮罩的最终缩放值是硬编码的,在平板设备上可能无法完整显示内容。根据屏幕尺寸和图像大小动态计算最终缩放值会是很棒的PR改进

React Native 月刊 #6

· 1 分钟阅读
Tomislav Tenodi
Speck 创始人
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

React Native 月度会议仍在火热进行中!请务必查看本文底部的通知以了解下一期会议安排。

Expo

  • 恭喜 Devin AbbottHoussein Djirdeh 预发布了《Full Stack React Native》一书!该书通过构建多个小型应用带你系统学习 React Native。

  • 发布了首个(实验性)版本的 reason-react-native-scripts,帮助开发者轻松尝试 ReasonML

  • Expo SDK 24 已发布!该版本基于 React Native 0.51,包含多项新特性和改进:独立应用内置图片(无需首次加载缓存!)、图片处理 API(裁剪/缩放/旋转/翻转)、人脸识别 API、新版发布渠道功能(设置指定渠道的活跃版本并支持回滚)、用于追踪独立应用构建的网页仪表盘,以及修复了 OpenGL Android 实现与 Android 多任务处理的长期 bug 等。

  • 今年一月起,我们将向 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 运行时和 UIManager(例如 JavaScriptCore、Xamarin.Mac、Linux Gtk# 和 Samsung Tizen 等方案)。

Wix

  • Detox

    • 为了扩大端到端测试规模,我们正在努力减少 CI 时间消耗,目前正在为 Detox 开发并行化支持功能。
    • 已提交拉取请求,支持自定义构建变体(flavor builds),以优化端到端测试的模拟环境。
  • DetoxInstruments

    • DetoxInstruments 的核心功能开发面临重大技术挑战:实现任意时刻 JavaScript 堆栈追踪需要定制 JSCore 以支持 JS 线程挂起机制。在 Wix 应用内部测试分析器时,我们获得了关于 JS 线程的宝贵洞察。
    • 该项目目前尚未达到稳定可用状态,但团队正积极投入研发,期待尽快发布正式公告。
  • React Native Navigation

    • V2 版本开发进度显著加速:此前仅由 1 名开发者投入 20% 时间维护,现已有 3 名开发者全职投入研发!
  • Android 性能优化

    • 将 React Native 内置的旧版 JSCore 替换为最新版本(基于 webkitGTK 项目尖端版本,采用定制化 JIT 配置),使 JS 线程性能提升 40%。下一步将编译其 64 位版本。该工作基于JSC Android 构建脚本,可通过此链接追踪当前进展。

后续会议安排

我们正讨论调整会议形式:未来可能聚焦单一特定主题(例如导航架构、React Native 模块独立仓库迁移、文档优化等)。这种方式有望最大化对 React Native 社区的贡献。该调整可能于下次会议实施,欢迎通过推特留言提出您希望探讨的主题。

React Native 月报 #5

· 1 分钟阅读
Tomislav Tenodi
Speck 创始人
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

新一期 React Native 月度会议来了!让我们看看各个团队的最新进展。

Callstack

  • 我们持续优化 React Native 的持续集成系统。最重要的进展是将 CI 系统从 Travis 迁移到 CircleCI,为 React Native 建立了统一高效的 CI 流水线。

  • 我们举办了 Hacktoberfest - React Native 特别版活动,与参与者共同向开源项目提交了大量 Pull Request。

  • 我们持续推进 Haul 项目。上月发布的两个新版本已支持 webpack 3。未来计划增加 CRNAExpo 支持,并优化热模块替换功能。路线图已在 issue 跟踪器公开。欢迎提出改进建议或反馈意见!

Expo

  • 发布 Expo SDK 22(基于 React Native 0.49)并同步更新 CRNA

    • 包含改进的启动屏 API、基础 ARKit 支持、"DeviceMotion" API、iOS11 的 SFAuthenticationSession 支持等新特性
  • Snack 编辑器现支持多 JavaScript 文件,并可通过拖拽直接上传图片等资源

  • react-navigation 贡献代码,新增 iPhone X 支持

  • 重点优化大型 Expo 应用的开发体验:

    • 提供多环境部署支持:预发布环境、生产环境及自定义渠道。渠道将支持版本回滚和动态切换。欢迎通过 @expo_io 申请成为内测用户
    • 改进独立应用构建流程,在保持 OTA 更新能力的同时支持静态资源打包

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" 的原有含义将被逐步废弃。未来几个月将取消交换逻辑,确保 "left" 始终代表左侧,"right" 始终代表右侧。开发者可通过 I18nManager.swapLeftAndRightInRTL(false) 提前启用此变更
  • 我们正在为内部原生模块添加 Flow 类型注解,并利用这些类型生成 Java 接口和 ObjC 协议,原生实现必须遵循这些规范。我们希望该代码生成工具最早能在明年开源。

Infinite Red

  • 发布了新的开源工具,用于辅助 React Native 及其他项目开发。详情请见此处

  • 正在重构 Ignite,准备发布新版脚手架(代号:Bowser)

Shoutem

  • 优化 Shoutem 平台的开发流程。我们致力于简化从创建应用到实现首个自定义屏幕的全过程,大幅降低 React Native 新手的入门门槛。通过多次工作坊测试了新功能,同时改进了 Shoutem CLI 以支持新流程。

  • Shoutem UI 进行了多项组件优化和错误修复,并验证了与最新 React Native 版本的兼容性。

  • Shoutem 平台迎来多项重要更新,新集成功能已作为开源扩展项目开放使用。看到其他开发者积极参与扩展开发令人振奋,我们主动联系并提供技术指导支持。

下一次会议

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

React Native 月度动态 #4

· 1 分钟阅读
Mike Grabowski
Mike Grabowski
CTO and Co-Founder @ Callstack
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

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 的支持,包含多项错误修复/稳定性提升/新功能:视频录制、全新启动屏 API、react-native-gesture-handler 支持及增强的错误处理机制。

  • 关于 react-native-gesture-handler:来自 Software MansionKrzysztof Magiera 持续推动该项目进展,我们协助进行了测试并资助了部分开发工作。SDK21 集成该库后,开发者可通过 Snack 轻松体验,期待看到大家的创意应用。

  • 关于错误日志/处理机制优化:日志改进细节请参考 Expo 内部 PR 摘要(重点关注"问题 2"),处理 npm 标准库模块导入失败的变更详见 此提交记录。React Native 上游仍有大量优化错误提示的空间,我们将跟进相关 PR,也欢迎社区参与贡献。

  • native.directory 持续扩展中,可通过 GitHub 仓库提交您的项目。

  • 正参与北美多地黑客马拉松活动,包括 PennAppsHack The NorthHackMIT,即将亮相 MHacks

Facebook

  • 正在优化 Android 平台的 <Text><TextInput> 组件(包括 <TextInput> 原生自适应高度、深层嵌套 <Text> 布局问题、代码结构优化及性能提升)。

  • 持续招募协助分类 issues 和处理 pull requests 的贡献者。

Microsoft

  • 发布了 CodePush 的代码签名功能。React Native 开发者现在可以为 CodePush 中的应用包进行签名。相关公告可在此查看

  • 正在完成 CodePush 与 Mobile Center 的集成工作,同时考虑整合测试/崩溃报告功能

下一次会议

下次会议定于 2017 年 10 月 10 日星期三举行。由于目前仅召开过四次会议,我们非常希望了解这些会议记录对 React Native 社区的价值。如果您对如何改进会议产出有任何建议,欢迎在 Twitter 上联系我