跳到主要内容

React Native 月报 #1

·6 分钟阅读
Tomislav Tenodi
Shoutem 产品经理

Shoutem,我们很幸运地从 React Native 的早期阶段就开始使用它。我们决定从第一天起就成为这个优秀社区的一部分。很快,我们意识到要跟上社区发展和改进的速度几乎是不可能的。这就是为什么我们决定组织一个每月会议,让所有主要的 React Native 贡献者可以简要介绍他们的工作和计划。

每月会议

我们在 2017 年 6 月 14 日举行了第一次月度会议。React Native 每月会议的使命简单明了:改善 React Native 社区。展示团队的努力有助于团队之间进行线下协作。

团队

在第一次会议上,有8个团队加入了我们

我们希望有更多的核心贡献者加入接下来的会议!

备忘

由于团队的计划可能会引起更广泛受众的兴趣,我们将在这里,在 React Native 博客上分享它们。所以,它们来了

Airbnb

  • 计划为 ViewAccessibilityInfo 原生模块添加一些 A11y(可访问性)API。
  • 将调查在 Android 上为原生模块添加一些 API,以允许指定它们运行的线程。
  • 一直在调查潜在的初始化性能改进。
  • 一直在调查一些更复杂的打包策略,以便在“unbundle”之上使用。

Callstack

  • 正在研究通过使用 Detox 进行 E2E 测试来改进发布流程。拉取请求应该很快就会合并。
  • 他们一直在开发的 Blob 拉取请求已合并,后续拉取请求即将到来。
  • 在内部项目中增加 Haul 的采用,以观察其与 Metro Bundler 相比的性能。与 webpack 团队合作,以提高多线程性能。
  • 在内部,他们已经建立了一个更好的基础设施来管理开源项目。计划在未来几周内推出更多内容。
  • React Native Europe 会议即将举行,目前还没有特别有趣的内容,但欢迎大家参加!
  • 暂时退出了 react-navigation 一段时间,以调查替代方案(特别是原生导航)。

Expo

  • 正在努力使 Snack 中可以安装 npm 模块,这对于库来说,在文档中添加示例将非常有用。
  • KrzysztofSoftware Mansion 的其他人合作,进行 Android 上的 JSC 更新和手势处理库的开发。
  • Adam Miskiewicz 正在将他的重心转向 react-navigation
  • Create React Native App 已收录在文档的入门指南中。Expo 希望鼓励库作者明确说明他们的库是否适用于 CRNA,如果适用,请解释如何进行设置。

Facebook

  • React Native 的打包器现在是 Metro Bundler,位于一个独立的仓库中。Metro Bundler 团队在伦敦很高兴能满足社区的需求,改进模块化以支持 React Native 之外的更多用例,并提高对问题和 PR 的响应速度。
  • 在接下来的几个月里,React Native 团队将致力于完善原始组件的 API。预计在布局怪癖、可访问性和流程类型方面会有改进。
  • React Native 团队还计划今年通过重构来改进核心模块化,以完全支持 Windows 和 macOS 等第三方平台。

GeekyAnts

  • 团队正在开发一款 UI/UX 设计应用程序(代号:Builder),它直接处理 .js 文件。目前,它只支持 React Native。它类似于 Adobe XD 和 Sketch。
  • 团队正在努力工作,以便您可以在编辑器中加载现有的 React Native 应用程序,进行更改(以设计师的视角进行视觉更改),并将更改直接保存到 JS 文件中。
  • 大家正在努力弥合设计师和开发者之间的差距,并将他们带到同一个代码仓库中。
  • 此外,NativeBase 最近达到了 5,000 个 GitHub 星。

Microsoft

  • CodePush 现已集成到 Mobile Center 中。这是提供与分发、分析和其他服务更集成体验的第一步。请在此处查看他们的公告。
  • VS Code 在调试方面存在一个 bug,他们正在努力修复,并将发布新的构建版本。
  • 正在研究 Detox 进行集成测试,并研究 JSC Context 以获取变量和崩溃报告。

Shoutem

  • 使用 React Native 社区的工具,让 Shoutem 应用的开发变得更轻松。您将能够使用所有 React Native 命令来运行在 Shoutem 上创建的应用。
  • 正在研究 React Native 的性能分析工具。他们在设置时遇到了很多问题,并将撰写他们在此过程中发现的一些见解。
  • Shoutem 正在努力使 React Native 与现有原生应用程序的集成变得更容易。他们将记录公司内部开发的概念,以获取社区的反馈。

Wix

  • Wix 内部正在努力采用 Detox,以将 Wix 应用的很大一部分转变为“零手动 QA”。因此,Detox 正在被数十位开发者在生产环境中大量使用,并迅速成熟。
  • 正在努力为 Metro Bundler 添加支持,以在构建期间覆盖任何文件扩展名。它将支持任何自定义扩展名,如“e2e”或“detox”,而不仅仅是“ios”和“android”。计划将其用于 E2E 模拟。已经有一个名为 react-native-repackager 的库,现在正在处理 PR。
  • 正在研究性能测试自动化。这是一个名为 DetoxInstruments 的新仓库。您可以查看一下,它正在开源开发中。
  • 与 KPN 的一位贡献者合作,开发适用于 Android 的 Detox 并支持真实设备。
  • 正在考虑将“Detox 作为一个平台”,以允许构建其他需要自动化模拟器/设备的工具。一个例子是 Storybook for React Native 或 Ram 的集成测试想法。

下一次会议

会议将每四周举行一次。下一次会议定于 2017 年 7 月 12 日举行。由于我们刚开始召开这个会议,我们想知道这些笔记如何有益于 React Native 社区。如果您对我们在接下来的会议中应该涵盖的内容,或者我们应该如何改进会议的输出有任何建议,请随时在 Twitter 上给我发消息

React Native 中更好的列表视图

·6 分钟阅读

在社区群组中发布预告后,许多人已经开始试用我们新的列表组件,但我们今天才正式宣布它们!不再有 ListViewDataSource,不再有陈旧的行、被忽略的 bug 或过度的内存消耗——随着最新的 React Native 2017 年 3 月发布候选版本 (0.43-rc.1) 的发布,您可以从新的组件套件中选择最适合您用例的组件,它们都具有出色的性能和开箱即用的功能集。

<FlatList>

这是用于简单、高性能列表的主力组件。提供一个数据数组和一个renderItem函数,就可以开始使用了。

<FlatList
data={[{title: 'Title Text', key: 'item1'}, ...]}
renderItem={({item}) => <ListItem title={item.title} />}
/>

<SectionList>

如果您想渲染一组数据,这些数据被分成逻辑部分,可能带有部分标题(例如,按字母顺序排列的地址簿),并且可能具有异构数据和渲染(例如,一个个人资料视图,带有一些按钮,然后是一个编辑器,然后是一个照片网格,然后是一个朋友网格,最后是故事列表),这就是您的最佳选择。

<SectionList
renderItem={({item}) => <ListItem title={item.title} />}
renderSectionHeader={({section}) => <H1 title={section.key} />}
sections={[ // homogeneous rendering between sections
{data: [...], key: ...},
{data: [...], key: ...},
{data: [...], key: ...},
]}
/>

<SectionList
sections={[ // heterogeneous rendering between sections
{data: [...], key: ..., renderItem: ...},
{data: [...], key: ..., renderItem: ...},
{data: [...], key: ..., renderItem: ...},
]}
/>

<VirtualizedList>

更灵活的 API 的幕后实现。如果您的数据不是纯数组(例如,一个不可变列表),则特别方便。

特性

列表在许多情况下使用,因此我们为新组件提供了许多功能,以处理大多数开箱即用的用例。

  • 滚动加载 (onEndReached)。
  • 下拉刷新 (onRefresh / refreshing)。
  • 可配置的可见性 (VPV) 回调 (onViewableItemsChanged / viewabilityConfig)。
  • 水平模式 (horizontal)。
  • 智能项目和节分隔符。
  • 多列支持 (numColumns)
  • scrollToEndscrollToIndexscrollToItem
  • 更好的 Flow 类型。

一些注意事项

  • 当内容滚动出渲染窗口时,项目子树的内部状态不会保留。确保所有数据都捕获在项目数据或外部存储中,如 Flux、Redux 或 Relay。

  • 这些组件基于 PureComponent,这意味着如果 props 保持浅层相等,它们将不会重新渲染。确保 renderItem 函数直接依赖的所有内容都作为在更新后不为 === 的 prop 传递,否则您的 UI 可能不会随着更改而更新。这包括 data prop 和父组件状态。例如

    <FlatList
    data={this.state.data}
    renderItem={({item}) => (
    <MyItem
    item={item}
    onPress={() =>
    this.setState(oldState => ({
    selected: {
    // New instance breaks `===`
    ...oldState.selected, // copy old data
    [item.key]: !oldState.selected[item.key], // toggle
    },
    }))
    }
    selected={
    !!this.state.selected[item.key] // renderItem depends on state
    }
    />
    )}
    selected={
    // Can be any prop that doesn't collide with existing props
    this.state.selected // A change to selected should re-render FlatList
    }
    />
  • 为了限制内存和实现流畅滚动,内容会在屏幕外异步渲染。这意味着滚动速度可能快于填充速度,并短暂地看到空白内容。这是一个可以根据每个应用程序的需求进行调整的权衡,我们正在幕后努力改进它。

  • 默认情况下,这些新列表会在每个项目上查找一个key prop,并将其用作 React 键。或者,您可以提供一个自定义的keyExtractor prop。

性能

除了简化 API,新的列表组件还具有显著的性能增强,其中最主要的是对于任意数量的行,内存使用几乎恒定。这是通过“虚拟化”渲染窗口之外的元素来实现的,即从组件层次结构中完全卸载它们并回收 React 组件的 JS 内存,以及影子树和 UI 视图的本机内存。这有一个缺点,即内部组件状态将不会被保留,因此请确保您在组件本身之外跟踪任何重要的状态,例如在 Relay、Redux 或 Flux 存储中。

限制渲染窗口还可以减少 React 和原生平台需要完成的工作量,例如视图遍历。即使您正在渲染一百万个元素中的最后一个,使用这些新列表,也无需遍历所有这些元素即可渲染。您甚至可以使用 scrollToIndex 跳转到中间而不会进行过度的渲染。

我们还对调度进行了一些改进,这应该有助于提高应用程序的响应能力。渲染窗口边缘的项很少渲染,并且在任何活动手势、动画或其他交互完成后以较低的优先级渲染。

高级用法

ListView 不同,渲染窗口中的所有项在任何 props 更改时都会重新渲染。通常这没问题,因为窗口化将项的数量减少到常数,但如果您的项比较复杂,您应该确保遵循 React 性能的最佳实践,并在您的组件中使用 React.PureComponent 和/或 shouldComponentUpdate 以限制递归子树的重新渲染。

如果您可以在不渲染行的情况下计算行的高度,您可以通过提供 getItemLayout prop 来改善用户体验。这使得使用 scrollToIndex 等滚动到特定项时更加平滑,并且会改善滚动指示器 UI,因为可以在不渲染内容的情况下确定内容的高度。

如果您有替代数据类型,例如不可变列表,则<VirtualizedList>是最佳选择。它接受一个getItem prop,允许您返回任何给定索引的项目数据,并且具有更宽松的 Flow 类型。

如果您有不寻常的用例,还可以调整许多参数。例如,您可以使用 windowSize 来权衡内存使用和用户体验,使用 maxToRenderPerBatch 来调整填充率和响应性,使用 onEndReachedThreshold 来控制何时发生滚动加载等等。

未来工作

  • 现有界面的迁移(最终废弃ListView)。
  • 根据我们的需求/意见增加更多功能(请告诉我们!)。
  • 粘性节标题支持。
  • 更多性能优化。
  • 支持带状态的功能项目组件。

idx:存在函数

·阅读时长2分钟
Timothy Yung
Facebook 工程经理

在 Facebook,我们经常需要访问通过 GraphQL 获取的数据结构中深度嵌套的值。在访问这些深度嵌套的值时,一个或多个中间字段常常是可为空的。这些中间字段为空的原因有很多,从隐私检查失败到仅仅是因为 null 是表示非致命错误最灵活的方式。

不幸的是,访问这些深度嵌套的值目前既繁琐又冗长。

props.user &&
props.user.friends &&
props.user.friends[0] &&
props.user.friends[0].friends;

有一个 ECMAScript 提案旨在引入存在运算符,这将使这种情况方便得多。但在该提案最终确定之前,我们希望有一个解决方案能够提高我们的生活质量,保持现有的语言语义,并鼓励 Flow 的类型安全。

我们想出了一个名为 idx 的存在性函数

idx(props, _ => _.user.friends[0].friends);

此代码片段中的调用与上面代码片段中的布尔表达式的行为类似,但重复性大大降低。idx 函数严格接受两个参数

  • 任何值,通常是您要访问嵌套值的对象或数组。
  • 一个函数,它接收第一个参数并访问其上的嵌套值。

理论上,idx 函数将尝试捕获由于访问 null 或 undefined 上的属性而导致的错误。如果捕获到此类错误,它将返回 null 或 undefined。(您可以在 idx.js 中查看如何实现这一点。)

实际上,对每个嵌套属性访问进行 try-catch 是缓慢的,并且区分特定类型的 TypeError 是脆弱的。为了解决这些缺点,我们创建了一个 Babel 插件,将上述 idx 调用转换为以下表达式

props.user == null
? props.user
: props.user.friends == null
? props.user.friends
: props.user.friends[0] == null
? props.user.friends[0]
: props.user.friends[0].friends;

最后,我们为 idx 添加了一个自定义的 Flow 类型声明,允许在第二个参数中进行遍历的类型检查,同时允许对可空属性进行嵌套访问。

该函数、Babel 插件和 Flow 声明现已 在 GitHub 上提供。它们通过安装 idxbabel-plugin-idx npm 包,并将“idx”添加到 .babelrc 文件中的插件列表中来使用。

引入 Create React Native App

·3 分钟阅读
Adam Perry
Expo 软件工程师

今天我们宣布推出 Create React Native App:一个新工具,可以大大简化 React Native 项目的入门!它深受 Create React App 设计的启发,是 FacebookExpo(前身为 Exponent)合作的产物。

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

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

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

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

原生代码怎么办?

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

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

有问题?反馈?

Create React Native App 现在已足够稳定,可供一般使用,这意味着我们非常渴望听到您使用它的体验!您可以在 Twitter 上找到我,或在 GitHub 存储库上提出问题。非常欢迎拉取请求!

使用原生驱动动画

·6 分钟阅读
Janic Duplessis
App & Flow 软件工程师

在过去的一年里,我们一直致力于提高使用 Animated 库的动画性能。动画对于创造出色的用户体验至关重要,但也很难做好。我们希望让开发人员能够轻松创建高性能动画,而不必担心他们的某些代码会导致动画卡顿。

这是什么?

Animated API 的设计考虑了一个非常重要的限制,即它是可序列化的。这意味着我们可以在动画开始之前将动画的所有内容发送到原生层,并允许原生代码在 UI 线程上执行动画,而无需在每一帧都经过桥接。这非常有用,因为一旦动画开始,JS 线程就可以被阻塞,动画仍然会流畅运行。实际上,这经常发生,因为用户代码在 JS 线程上运行,并且 React 渲染也可能长时间锁定 JS 线程。

一点历史...

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

它是如何工作的?

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

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

  • JS:动画驱动器使用 requestAnimationFrame 在每一帧执行,并根据动画曲线计算出的新值更新它驱动的值。
  • JS:计算中间值并将其传递给附加到 View 的 props 节点。
  • JS:使用 setNativeProps 更新 View
  • JS 到原生桥。
  • 原生:更新 UIViewandroid.View

如您所见,大部分工作都在 JS 线程上进行。如果它被阻塞,动画将跳帧。它还需要在每一帧通过 JS 到原生桥来更新原生视图。

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

以下是我们如何序列化动画值和插值节点的示例(不是确切的实现,只是一个示例)。

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

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

创建原生插值节点,这告诉原生驱动程序如何插值一个值

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

创建原生 props 节点,这告诉原生驱动程序它附加到视图的哪个 props

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

连接节点

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

将 props 节点连接到视图

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

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

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

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

现在是动画运行时发生的事情的分解

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

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

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

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

之前

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

之后

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

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

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

之前

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

之后

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

注意事项

并非所有可以使用 Animated 实现的功能目前都受 Native Animated 支持。主要的限制是您只能动画非布局属性,例如 transformopacity 会起作用,但 Flexbox 和 position 属性不会。另一个是 Animated.event,它只适用于直接事件,而不适用于冒泡事件。这意味着它不适用于 PanResponder,但适用于 ScrollView#onScroll 等。

Native Animated 也已成为 React Native 的一部分很长时间了,但由于被认为是实验性的,从未被记录。因此,如果您想使用此功能,请确保您使用的是最新版本 (0.40+) 的 React Native。

资源

有关动画的更多信息,我建议观看 Christopher Chedeau 的这个演讲

如果您想深入了解动画以及如何将其卸载到原生以改善用户体验,还可以观看 Krzysztof Magiera 的这个演讲

每月发布周期:发布 12 月和 1 月 RC

·3 分钟阅读
Eric Vicenti
Facebook 工程师

在 React Native 推出后不久,我们开始每两周发布一次,以帮助社区采用新功能,同时保持版本稳定以供生产使用。在 Facebook,我们每两周需要稳定一次代码库,以便发布我们的生产 iOS 应用程序,因此我们决定以相同的速度发布开源版本。现在,许多 Facebook 应用程序每周发布一次,尤其是在 Android 上。由于我们每周从主分支发布,因此我们需要保持它相当稳定。因此,每两周发布一次的节奏甚至不再对内部贡献者有益。

我们经常从社区听到反馈说发布速度难以跟上。Expo 等工具不得不跳过每次发布,以管理版本的快速变化。因此,很明显,每两周发布一次对社区并没有起到很好的作用。

现在每月发布

我们很高兴地宣布新的每月发布节奏,以及 2016 年 12 月发布的 v0.40,它在上个月已经稳定下来并准备好采用。(请务必更新 iOS 上原生模块中的头文件)。

尽管可能会有几天误差以避免周末或处理意外问题,但您现在可以预期某个版本将在该月的第一天可用,并在该月的最后一天发布。

使用当月的版本以获得最佳支持

一月份的候选版本已准备好尝试,您可以在此处查看新内容

为了查看即将到来的变化并向 React Native 贡献者提供更好的反馈,请尽可能始终使用当月的发布候选版本。到月底发布每个版本时,其中包含的更改将已在生产 Facebook 应用程序中发布超过两周。

您可以使用新的 react-native-git-upgrade 命令轻松升级您的应用程序

npm install -g react-native-git-upgrade
react-native-git-upgrade 0.41.0-rc.0

我们希望这种更简单的方法将使社区更容易跟踪 React Native 中的变化,并尽可能快地采用新版本!

(感谢 Martin Konicek 提出此计划,以及 Mike Grabowski 使其实现)

借助 Git 更轻松地升级

·阅读时长5分钟
Nicolas Cuillery
Zenika 的 JavaScript 顾问和培训师

升级到新版本的 React Native 一直很困难。您可能以前见过类似这样的内容

这些选项都不理想。通过覆盖文件,我们会丢失本地更改。不覆盖则无法获得最新更新。

今天,我很高兴推出一个有助于解决此问题的新工具。该工具名为 react-native-git-upgrade,它在后台使用 Git 尽可能自动解决冲突。

用法

要求:Git 必须在 PATH 中可用。您的项目无需由 Git 管理。

全局安装 react-native-git-upgrade

$ npm install -g react-native-git-upgrade

或者,使用 Yarn

$ yarn global add react-native-git-upgrade

然后,在您的项目目录中运行它

$ cd MyProject
$ react-native-git-upgrade 0.38.0

注意:请勿运行 'npm install' 来安装新版本的 react-native。该工具需要能够比较旧的和新的项目模板才能正常工作。只需在您的应用程序文件夹中运行它,如上所示,同时仍处于旧版本。

输出示例

您也可以在不带任何参数的情况下运行 react-native-git-upgrade,以升级到最新版本的 React Native。

我们尝试保留您在 Android 和 iOS 构建文件中的更改,因此升级后您无需运行 react-native link

我们设计的实现尽可能少地侵入。它完全基于在临时目录中即时创建的本地 Git 仓库。它不会干扰您的项目仓库(无论您使用什么 VCS:Git、SVN、Mercurial,...或不使用)。如果发生意外错误,您的源代码将得到恢复。

它是如何工作的?

关键步骤是生成一个 Git 补丁。该补丁包含 React Native 模板在您的应用程序所用版本和新版本之间发生的所有更改。

为了获得此补丁,我们需要从 node_modules 目录中 react-native 包内嵌的模板生成一个应用程序(这些模板与 react-native init 命令使用的模板相同)。然后,在当前版本和新版本都从模板生成了原生应用程序后,Git 能够生成一个适合您项目的补丁(即包含您的应用程序名称)

[...]

diff --git a/ios/MyAwesomeApp/Info.plist b/ios/MyAwesomeApp/Info.plist
index e98ebb0..2fb6a11 100644
--- a/ios/MyAwesomeApp/Info.plist
+++ b/ios/MyAwesomeApp/Info.plist
@@ -45,7 +45,7 @@
<dict>
<key>localhost</key>
<dict>
- <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
+ <key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
[...]

我们现在需要做的就是将此补丁应用到您的源文件。虽然旧的 react-native upgrade 过程会提示您任何细微的差异,但 Git 能够使用其三向合并算法自动合并大部分更改,并最终给我们留下熟悉的冲突分隔符

    13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
<<<<<<< ours
CODE_SIGN_IDENTITY = "iPhone Developer";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/HockeySDK.embeddedframework",
"$(PROJECT_DIR)/HockeySDK-iOS/HockeySDK.embeddedframework",
);
=======
CURRENT_PROJECT_VERSION = 1;
>>>>>>> theirs
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../node_modules/react-native/React/**",
"$(SRCROOT)/../node_modules/react-native-code-push/ios/CodePush/**",
);

这些冲突通常很容易理解。分隔符 **ours** 代表“您的团队”,而 **theirs** 可以看作是“React Native 团队”。

为什么要引入一个新的全局包?

React Native 带有一个全局 CLI(react-native-cli 包),它将命令委托给嵌入在 node_modules/react-native/local-cli 目录中的本地 CLI。

如上所述,该过程必须从您当前的 React Native 版本开始。如果我们将实现嵌入到 local-cli 中,那么在使用旧版本 React Native 时您将无法享受到此功能。例如,如果这个新的升级代码只在 0.38.0 中发布,您将无法从 0.29.2 升级到 0.38.0。

基于 Git 的升级是开发人员体验的一大改进,让所有人都能使用它很重要。通过安装全局的独立包 react-native-git-upgrade,您今天就可以使用这个新代码,无论您的项目使用哪个版本的 React Native。

另一个原因是 Martin Konicek 最近的 Yeoman 清除。我们不想将这些 Yeoman 依赖项重新带回 react-native 包中,以便能够评估旧模板以创建补丁。

试用并提供反馈

总而言之,我会说,享受这个功能,并随时提出改进建议,报告问题,尤其是发送拉取请求。每个环境都有些不同,每个 React Native 项目也都不同,我们需要您的反馈才能让它对每个人都有效。

谢谢!

我要感谢很棒的公司 ZenikaM6 Web (已存档),没有他们,这一切都不可能实现!

引入 Button、使用 Yarn 更快的安装以及公开路线图

·3 分钟阅读
Héctor Ramos
Héctor Ramos
前 Facebook 开发者倡导者

我们从许多人那里了解到,React Native 正在进行大量工作,很难追踪正在发生的事情。为了帮助沟通正在进行的工作,我们现在发布了React Native 路线图。从高层来看,这项工作可以分为三个优先事项。

  • 核心库。为最有用的组件和 API 添加更多功能。
  • 稳定性。改进底层基础设施,减少错误并提高代码质量。
  • 开发者体验。帮助 React Native 开发者更快地行动。

如果您对您认为有价值的路线图功能有任何建议,请查看 Canny,您可以在其中建议新功能并讨论现有提案。

React Native 有哪些新功能

今天发布的 React Native 0.37 版本引入了一个新的核心组件,使得向任何应用添加可触摸的 Button 变得非常容易。我们还引入了对新Yarn 包管理器的支持,这应该会加速更新应用程序依赖项的整个过程。

引入 Button

今天我们引入了一个基本的 <Button /> 组件,它在所有平台上都表现出色。这解决了我们收到的最常见的反馈之一:React Native 是少数没有开箱即用的按钮的移动开发工具包之一。

Simple Button on Android, iOS

<Button
onPress={onPressMe}
title="Press Me"
accessibilityLabel="Learn more about this Simple Button"
/>

经验丰富的 React Native 开发者知道如何制作一个按钮:在 iOS 上使用 TouchableOpacity 实现默认外观,在 Android 上使用 TouchableNativeFeedback 实现波纹效果,然后应用一些样式。自定义按钮并不特别难构建或安装,但我们的目标是使 React Native 变得极其容易学习。通过在核心中添加一个基本按钮,新手将能够在他们的第一天开发出一些很棒的东西,而不是将时间花在格式化 Button 和学习 Touchable 的细微差别上。

Button 旨在在每个平台上都能很好地工作并看起来原生,因此它不支持自定义按钮所具有的所有花哨功能。它是一个很好的起点,但并非旨在取代您所有现有的按钮。要了解更多信息,请查看新的 Button 文档,其中包含一个可运行的示例!

使用 Yarn 加速 react-native init

您现在可以使用 JavaScript 的新包管理器 Yarn,显着加快 react-native init。要查看加速效果,请安装 yarn 并将您的 react-native-cli 升级到 1.2.0

$ npm install -g react-native-cli

现在,在设置新应用时,您应该会看到“Using yarn”(正在使用 yarn)。

Using yarn

在简单的本地测试中,react-native init良好的网络条件下大约 1 分钟内完成(而使用 npm 3.10.8 时大约需要 3 分钟)。安装 yarn 是可选的,但强烈推荐。

谢谢!

我们要感谢所有为本次发布做出贡献的人。完整的发布说明现已在 GitHub 上提供。凭借二十多个错误修复和新功能,React Native 在您的帮助下不断变得更好。

0.36:无头 JS、键盘 API 等

·3 分钟阅读
Héctor Ramos
Héctor Ramos
前 Facebook 开发者倡导者

今天我们发布了 React Native 0.36。继续阅读以了解新功能。

无头 JS

无头 JS 是一种在您的应用程序处于后台时在 JavaScript 中运行任务的方式。例如,它可用于同步新数据、处理推送通知或播放音乐。目前,它仅在 Android 上可用。

要开始使用,请在专用文件(例如 SomeTaskName.js)中定义您的异步任务

module.exports = async taskData => {
// Perform your task here.
};

接下来,在 AppRegistry 上注册您的任务

AppRegistry.registerHeadlessTask('SomeTaskName', () =>
require('SomeTaskName'),
);

使用无头 JS 需要编写一些原生 Java 代码,以便您可以在需要时启动服务。查看我们新的 无头 JS 文档 以了解更多信息!

键盘 API

现在使用 Keyboard 可以更轻松地处理屏幕键盘。您现在可以监听原生键盘事件并对其作出反应。例如,要关闭活动的键盘,只需调用 Keyboard.dismiss()

import {Keyboard} from 'react-native';

// Hide that keyboard!
Keyboard.dismiss();

动画除法

React Native 已经支持通过加法、乘法和模运算组合两个动画值。在版本 0.36 中,现在可以通过除法组合两个动画值。在某些情况下,动画值需要反转另一个动画值进行计算。一个例子是反转比例 (2x --> 0.5x)

const a = Animated.Value(1);
const b = Animated.divide(1, a);

Animated.spring(a, {
toValue: 2,
}).start();

b 将跟随 a 的弹性动画并生成 1 / a 的值。

基本用法如下

<Animated.View style={{transform: [{scale: a}]}}>
<Animated.Image style={{transform: [{scale: b}]}} />
<Animated.View>

在此示例中,内部图像根本不会被拉伸,因为父级的缩放被抵消了。如果您想了解更多信息,请查看 动画指南

深色状态栏

StatusBar 中添加了一个新的 barStyle 值:dark-content。通过此添加,您现在可以在 Android 和 iOS 上都使用 barStyle。行为现在将如下所示:

  • default:使用平台默认值(iOS 上为浅色,Android 上为深色)。
  • light-content:使用带有黑色文本和图标的浅色状态栏。
  • dark-content:使用带有白色文本和图标的深色状态栏。

……以及更多

以上只是 0.36 版本中更改的一小部分。请查看 GitHub 上的发行说明,以查看新功能、错误修复和重大更改的完整列表。

您可以通过在终端中运行以下命令升级到 0.36

$ npm install --save react-native@0.36
$ react-native upgrade