跳至主内容

发布 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.5、Android SDK 26、Fresco 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 核心团队将恢复举行月度会议。我们将确保及时同步会议讨论内容,并将您的反馈纳入未来会议考量。

祝大家编码愉快!

Lorenzo、Ryan 及全体 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 驱动。

当然,我们也使用其他多种技术构建应用。Litho 和 ComponentKit 是我们在应用中广泛使用的两个库;它们都提供类似 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.js、npm 和 Yarn。

初始化​

当您尝试搭建好普通 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.tsx。index.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',
},
});

哇!内容有点多,我们来分解说明:

  • 我们不再渲染 div、span、h1 等 HTML 元素,而是渲染 View 和 Button 等组件。这些是跨平台工作的原生组件。

  • 样式使用 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-manager、react-native-swipeable、react-native-gallery、react-native-view-transformer、react-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> 成为第一响应者时,底层会变成 UITextView 或 UITextField 实例。

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

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


此例中谁拥有 <InputAccessoryView>?还能是 UITextView 或 UITextField 吗?文本输入框竟_位于_ 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 的具体实现。例如,若您需要用户注册登录后上传私有照片,只需在应用中引入 Auth 和 Storage 类别:

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 DynamoDB、Amazon Elasticsearch 和 AWS 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 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 的交互,还实现了数据分页(含加密令牌)以及 Events 和 Comments 的类型关联。由于应用配置了 AWSAppSyncClient,数据会自动持久化离线存储,并在设备重连时同步更新。

您可以通过此技术深度解析视频查看客户端技术细节和 React Native 演示。

反馈​

这些库背后的团队渴望了解这些库和服务对您的工作效果如何。他们还想了解我们还能做些什么,让您在使用云服务开发 React 和 React Native 应用时更加轻松。请在 GitHub 上联系 AWS Mobile 团队:AWS Amplify 或 AWS 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 接收 maskElement 和 children 两个 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 的限制是只能修改特定属性(主要是 transform 和 opacity),目前无法用 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.View、Animated.Text和Animated.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 Abbott 和 Houssein 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-maps 和 react-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。未来计划增加 CRNA 和 Expo 支持,并优化热模块替换功能。路线图已在 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 Mansion 的 Krzysztof Magiera 持续推动该项目进展,我们协助进行了测试并资助了部分开发工作。SDK21 集成该库后,开发者可通过 Snack 轻松体验,期待看到大家的创意应用。

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

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

  • 正参与北美多地黑客马拉松活动,包括 PennApps、Hack The North、HackMIT,即将亮相 MHacks。

Facebook​

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

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

Microsoft​

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

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

下一次会议​

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