跳到主要内容

React Native 0.77 - 新的样式特性、Android 的 16KB 页面支持、Swift 模板

·15 分钟阅读
Vojtech Novak
Vojtech Novak
Expo 软件工程师
Mazen Chami
Mazen Chami
InfiniteRed 软件工程师
Blake Friedman
Blake Friedman
Meta 软件工程师
Rob Hogan
Rob Hogan
Meta 软件工程师

今天,我们激动地发布 React Native 0.77!

此版本发布了多项功能:新的样式功能,例如支持 display: contentsboxSizingmixBlendModeoutline 相关属性,以提供更强大的布局选项;Android 16KB 页面支持,以兼容较新的 Android 设备。我们还在现代化社区模板,将其迁移到 Swift,同时继续支持和维护与喜欢 Objective-C 的开发人员的兼容性。

亮点

重大变更

亮点

新的 CSS 特性,用于更好的布局、尺寸和混合

React Native 0.77 进一步推进了我们使 React Native 与 Web 对齐的目标。我们添加了对新的 CSS 属性的支持,使您可以更好地控制应用程序的布局、尺寸和混合。这些更改可以帮助简化复杂布局、添加纹理并使您的应用程序更易于访问。

信息

所有这些新功能仅适用于新架构

使用 display: contents 简化布局

display: contents 属性允许元素从布局结构中消失,而其子元素仍然像它们是父元素的直接子元素一样呈现。当您想要对子元素应用样式而不影响布局,构建必须处理事件的包装组件,或者如果您需要与 ShadowTree 交互时,它会很有用。

从技术上讲,display: contents 渲染元素而不生成布局框,但它保留元素子元素的布局框。具有 display: contents 的元素实际上从视图层次结构中扁平化。

让我们看一个示例,其中我们希望在按下小部件时显示警报。我们在容器视图中有一个红色 Widget

Container.jsx
function Container() {
return (
<View style={styles.container}>
<Widget />
</View>
);
}

display contents - setup

现在,让我们构建一个新的 Alerting 包装组件,目标是在按下其下方的组件时提醒用户,使用实验性指针事件。为了清晰起见,此组件的背景设置为蓝色。它可能看起来像下面的组件

Container.jsx
function Alerting({children}) {
return (
<View
style={{backgroundColor: 'blue'}}
onPointerDown={() => alert('Hello World!')}>
{children}
</View>
}

function Container() {
return (
<View style={styles.container}>
<Alerting>
<Widget />
</Alerting>
</View>
);
}

这并没有完全达到我们想要的效果。Alerting 添加了一个新的布局框,它有自己的边界,与子 Widget 分开。根据它包装的元素的样式,这可能会导致显着的视觉和功能变化。在此示例中,蓝色背景响应点击并发出警报,而我们希望只有红色“Hello World”框在被点击时发出警报。

before display contents

如果我们再次尝试,同时在 AlertingView 包装器上设置 display: contents,我们只会在用户在 Widget 的原始边界内按下时看到警报。这是因为 Alerting 不再添加自己的框,但仍然可以观察从 Widget 冒泡的指针事件。

Container.jsx
function Alerting({children}) {
return (
<View
style={{display: 'contents'}}
onPointerDown={() => alert('Hello World!')}>
{children}
</View>
);
}

// ... function Container ...

after display contents

Box sizing(盒模型尺寸)

boxSizing 属性定义了如何计算元素的各种尺寸属性(widthheightminWidthminHeight 等)。如果 boxSizingborder-box,则这些尺寸适用于元素的边框框。如果它是 content-box,则它们适用于元素的内容框。默认值为 border-box,这与 Web 上的默认值不同。如果您想了解有关此属性如何工作的更多信息,Web 文档是一个很好的信息来源。

警告

border-box 在这一点上一直是默认值,并且在添加 content-box 之前一直是唯一的 boxSizing 值。更改默认值将是一个重大变更,可能会突然破坏多个布局。我们决定保留 border-box 作为默认值,以确保向后兼容性。

要理解 border-boxcontent-box 之间的区别,请看以下示例,其中两个 View 都具有 padding: 20borderWidth: 10。当使用 border-box 时,我们在调整尺寸时考虑边框和内边距;当使用 content-box 时,我们仅在调整尺寸时考虑内容。

after display contents

CSS mixBlendMode(混合模式)

mixBlendMode 属性允许您控制元素如何将其颜色与其堆叠上下文中的其他元素混合。有关每种混合功能的完整概述,请查看 MDN 文档

为了帮助更精细地控制混合在一起的内容,我们还添加了 isolation 属性。在 View 上设置 isolation: isolate 将强制它形成一个堆叠上下文。因此,您可以在某些祖先 View 上设置此属性,以确保具有 mixBlendMode 的某些后代 View 不会超出隔离的 View 进行混合。

mixBlendMode 值
  • normal:元素绘制在其背景之上,不进行混合。
  • multiply:源颜色与目标颜色相乘,并替换目标。
  • screen:将背景和源颜色值的补色相乘,然后对结果求补色。
  • overlay:根据背景颜色值,将颜色相乘或滤色。
  • darken:选择背景和源颜色中较暗的颜色。
  • lighten:选择背景和源颜色中较浅的颜色。
  • color-dodge:使背景颜色变亮以反映源颜色。用黑色绘画不会产生任何变化。
  • color-burn:使背景颜色变暗以反映源颜色。用白色绘画不会产生变化。
  • hard-light:根据源颜色值,将颜色相乘或滤色。效果类似于在背景上照射强烈聚光灯。
  • soft-light:根据源颜色值,使颜色变暗或变亮。效果类似于在背景上照射柔和聚光灯。
  • difference:从较浅的颜色中减去两种组成颜色中较暗的颜色。
  • exclusion:产生类似于“差值”模式的效果,但对比度较低。
  • hue:创建一种颜色,该颜色具有源颜色的色调以及背景颜色的饱和度和亮度。
  • saturation:创建一种颜色,该颜色具有源颜色的饱和度以及背景颜色的色调和亮度。
  • color:创建一种颜色,该颜色具有源颜色的色调和饱和度以及背景颜色的亮度。这保留了背景的灰度级别,并且对于着色单色图像或为彩色图像着色很有用。
  • luminosity:创建一种颜色,该颜色具有源颜色的亮度以及背景颜色的色调和饱和度。这会产生与“颜色”模式相反的效果。

blend mode

Outline 属性(轮廓属性)

我们还引入了 outlineWidthoutlineStyleoutlineSpreadoutlineColor。这些轮廓属性的工作方式与各自的 border 属性非常相似,但它是在边框框周围而不是在内边距框周围渲染的。这些属性允许通过绘制元素的轮廓来突出显示元素,而不会影响其布局。

有关更多详细信息,请查看 MDN 文档

outline props

Android 版本 15 支持和 16KB 页面支持

在 Android 15 上强制 edge-to-edge(边缘到边缘)

在之前的版本中,我们已经完成了一些工作来支持 Android 15。Android 15 中最显着的变化之一是,当您使用 targetSdk 35 构建应用程序时,会强制进行 edge-to-edge 显示。

如果您尚未对此进行研究,请参阅我们之前的建议,了解应如何处理此问题,因为忽略此问题可能会破坏应用程序中的 UI。

注意

如果您在应用程序中使用 react-native-safe-area-context,则该库已经为您处理了强制 edge-to-edge。

Android 的 16 KB 页面大小支持

Android 15 引入了对 16KB 内存页面大小的支持,从而为应用程序实现了性能改进等,但使以前基于 4KB 的应用程序可能在未来的设备上不兼容;目前,对于开发人员来说,这是一个选择加入的功能,可以在选定的设备上进行测试,以便为 16 KB 页面大小成为操作系统默认设置做好准备。

在 0.77 版本中,React Native 已准备好完全支持 16 KB 页面大小,开发人员将能够使用它来测试和发布适用于 16 KB 设备的应用程序。

有关 16 KB 支持的更多信息,请参阅 官方 Android Developers 网站

社区 CLI 和模板更新

社区 CLI:react-native init 弃用

此版本完全完成了 React Native 0.75 中引入react-native init 命令的弃用。

作为提醒,您将无法再使用 react-native init 命令,但您必须执行以下操作之一

  • 使用框架,例如 Expo,及其自己的专用命令来创建新项目:npx create-expo-app
  • 使用 npx @react-native-community/cli init 直接调用社区 CLI

社区 CLI:从 Metro 中删除“在 iOS/Android 上运行”的按键处理程序

在此版本中,我们从 Metro 中移除了 ‘a’ 和 ‘i’ 键盘快捷键。这些快捷键用于调用 run-androidrun-ios 社区 CLI 命令。这些键盘快捷键提供了较差的开发者体验,并且很少使用。此外,我们认为框架更适合协调终端输出。

您可以在这篇专门的文章中阅读有关此更改的更多信息。

社区模板:Swift 作为 iOS 应用程序的编程语言

信息

使用 Expo 的项目不应受到此更改的影响。

此更改使我们能够通过用一个新的AppDelegate.swift 替换三个文件(main.mAppDelegate.hAppDelegate.mm)来简化社区模板。

从技术上讲,这是一个重大变更:您将在升级助手工具中看到从 Objective-C 到 Swift 的更改,如下所示

Swift Upgrade Helper

您不必迁移到 Swift:仍然支持 iOS 社区模板的 Objective-C++ 变体(请注意,您仍然需要集成 RCTAppDependencyProvider)。新的项目将使用 Swift 作为 iOS 应用程序语言生成,但如果需要,您可以随时迁移回 Objective-C。

局限性

如果您的应用程序有一些用 C++ 编写的本地模块,您将无法按照本指南所示在 Swift 中注册它们。

如果您的应用程序属于此类别,请跳过 AppDelegate 到 Swift 的迁移,并继续为您的应用程序使用 Objective-C++。

React Native 核心主要使用 C++ 开发,以鼓励 iOS 和 Android 以及其他平台之间的代码共享。Swift 和 C++ 之间的互操作性尚不成熟且不稳定。我们正在寻找方法来填补这一空白,并让您也可以迁移到 Swift。

RCTAppDependencyProvider

React Native 0.77 稍微更改了应用程序加载第三方依赖项的方式。这是社区模板中的新行,如果遗漏,可能会导致一些运行时问题。请确保将其添加到您的应用程序中。

等效的 Objective-C 行如下

AppDelegate.mm
#import "AppDelegate.h"

#import <React/RCTBundleURLProvider.h>
#import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>


@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.moduleName = @"<Your app Name>";
self.dependencyProvider = [RCTAppDependencyProvider new];
// You can add your custom initial props in the dictionary below.
// They will be passed down to the ViewController used by React Native.
self.initialProps = @{};

return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

// remaining of the AppDelegate

重大变更

移除 Metro 中的 console.log() 流式传输

我们希望 React Native 调试的每个方面都表现可靠,并与现代浏览器工具的功能相匹配。为了达到此质量标准,通过 Metro 进行的日志转发(最初在 0.76 中已弃用)在 0.77 中已移除。

此集成依赖于自定义方法来与设备上的调试目标进行通信。通过此更改,我们正在完全转向 Chrome DevTools Protocol (CDP)。

  • 要查看 JS 日志,请使用React Native DevTools及其功能齐全的控制台面板 — 支持日志过滤、丰富的对象检查、实时表达式等。
  • 您还可以通过第三方扩展(例如 Expo ToolsRadon IDE)将 VS Code 连接为 CDP 调试器。
    • 请注意,React 团队不直接支持这些集成。但是,我们正在努力在 2025 年实现第一方 VS Code 支持。
  • Expo 继续在 Expo CLI 中提供日志流式传输。

有关更多信息,请参阅为什么 JavaScript 日志要离开 Metro?

其他重大变更

通用

  • 动画
    • 原生循环动画在每次循环结束时不会发送 React 状态更新。
  • 布局
    • ScrollView 上粘性标题的 position 现在将被考虑在内。
    • 绝对定位现在的行为更加符合规范
  • JS 模块
    • 移除 ReactFabricInternals 模块
      • 这将不再可访问
  • 原生模块
    • NativeModules 对象现在可用于在 JS 中加载 turbomodules。
      • 这提高了原生模块和 Turbo 原生模块之间的兼容性
    • dev-middleware:框架应指定相对于中间件主机的 serverBaseUrl
  • API 变更
    • AppRegistry 中移除 useConcurrentRoot 的类型,因为它已被忽略
    • NativeMethods TypeScript 定义中移除 refs 属性。
  • UX 变更
    • 从开发服务器按键命令中移除“在 iOS 上运行”和“在 Android 上运行”

Android

  • Kotlin
    • 这是 React Native 的第一个版本,它基于 Kotlin 2.0.21 构建。您可以在语言发布说明中阅读有关 Kotlin 2.0 的更改的更多信息。
  • API 变更
    • 可空性
      • ReadableArray 中的非原始类型 getter 现在已正确类型化为可选
      • 使 ReactHost.createSurface() 方法不可为空
    • 已重命名
      • DevSupportManagerBase.getCurrentContext() 重命名为 DevSupportManagerBase.getCurrentReactContext()

此外,一些 API 已被删除或限制了可见性,因此无法再访问它们。这些 API 是内部的,React Native 开发人员不需要直接使用它们。您可以在下面找到完整列表

已移除的 Android API 列表

以下软件包现在是内部的,无法再访问

  • com.facebook.react.views.progressbar
  • com.facebook.react.views.safeareaview
  • com.facebook.react.modules.accessibilityinfo
  • com.facebook.react.modules.appstate
  • com.facebook.react.modules.clipboard
  • com.facebook.react.modules.devmodule
  • com.facebook.react.modules.reactdevtoolssettings
  • com.facebook.react.views.unimplementedview

以下类现在是内部的或已被删除,因此无法再访问

  • BackHandler.removeEventListener
  • BaseViewManagerInterface
  • BindingImpl
  • CompositeReactPackage
  • DebugOverlayTags
  • 来自 DefaultDevSupportManagerFactory 的方法 create()
  • DevToolsReactPerfLogger
  • FabricComponents
  • ImageStoreManager
  • InteropModuleRegistry
  • NativeModulePerfLogger
  • NoopPrinter
  • NotThreadSafeViewHierarchyUpdateDebugListener
  • OkHttpCallUtil
  • PrinterHolder
  • Printer
  • ReactDebugOverlayTags
  • ReactNativeFlipper
  • ReactViewBackgroundManager
  • ReactViewGroup.getBackgroundColor()
  • ReactVirtualTextShadowNode
  • ReactVirtualTextViewManager
  • SimpleSettableFuture
  • SwipeRefreshLayoutManager
  • TaskCompletionSource
  • 来自 DefaultReactHost.getDefaultReactHost() 的参数 jsBundleLoader

iOS

  • API 变更
    • 已移除
      • RCTConstants.RCTGetMemoryPressureUnloadLevel
      • partialBatchDidFlush
      • RCTRuntimeExecutor
      • UseNativeViewConfigsInBridgelessMode
        • 已替换为正确的特性标志
      • UseTurboModuleInteropForAllTurboModules
        • Interop 层始终为 TM 启用
    • 已更改
      • CGColorRef 的用法替换为 UIColor
  • RCTAppDelegate 现在需要使用 RCTDependencyProvider 来加载第三方依赖项
  • CocoaPods 为所有第三方依赖项设置 C++ 版本,以避免编译问题。
React 19?

React 19 于 2024 年 12 月 6 日发布。当时,我们已经为 React Native 0.77 切出了分支,并且已经发布了三个 React Native 0.77 的 RC 版本。在 React Native 0.77 的发布中引入 React 19 已经太晚了。

React 19 将在 React Native 0.78 中发布,我们已经为该版本切出了分支。您可以使用以下命令创建一个新应用程序来尝试它

npx @react-native-community/cli init YourReact19App --version 0.78.0-rc.0

致谢

React Native 0.77 包含来自 161 位贡献者的超过 1061 次提交。感谢大家辛勤的工作!

感谢所有为本发布文章记录特性做出贡献的其他作者

升级到 0.77

除了升级文档外,请使用 React Native 升级助手来查看现有项目的 React Native 版本之间的代码更改。

要创建新项目

npx @react-native-community/cli@latest init MyProject --version latest

如果您使用 Expo,Expo SDK 52 将支持 React Native 0.77(有关如何在您的 Expo 项目中将 React Native 更新到 0.77.0 的说明将在不久的将来在单独的 Expo 博客文章中提供)。

信息

0.77 现在是 React Native 的最新稳定版本,0.74.x 已变为不受支持。有关更多信息,请参阅 React Native 的支持策略。我们的目标是在不久的将来发布 0.74 的最终终止生命周期更新。