跳至主内容

React Native 0.77 - 全新样式功能、Android 16KB 页面支持、Swift 模板

· 1 分钟阅读
Vojtech Novak
Vojtech Novak
Software Engineer @ Expo
Mazen Chami
Mazen Chami
Software Engineer @ InfiniteRed
Blake Friedman
Blake Friedman
Software Engineer @ Meta
Rob Hogan
Rob Hogan
Software Engineer @ Meta
非官方测试版翻译

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

今天我们很高兴地发布 React Native 0.77!

本次发布包含多项功能:新增了样式能力,例如支持 display: contentsboxSizingmixBlendMode 以及 outline 相关属性,提供更强大的布局选项;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>
);
}

显示内容 - 设置

现在,让我们构建一个新的 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" 框在点击时触发警报。

使用 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 ...

应用display效果

盒模型尺寸计算

boxSizing属性决定元素尺寸属性(widthheightminWidthminHeight等)的计算方式。当boxSizing设为border-box时,尺寸包含边框区域;设为content-box时仅计算内容区域。默认值为border-box(与Web默认值不同)。若需深入了解其工作原理,可参考MDN文档

警告

border-box作为默认值沿用至今,在添加content-box之前一直是唯一支持的boxSizing值。若变更默认值将导致大量布局突然崩溃,因此我们保留border-box作为默认值以确保向后兼容。

要理解border-boxcontent-box之间的区别,请查看以下示例:两个View均设置padding: 20borderWidth: 10。使用border-box时尺寸包含边框和内边距;使用content-box时仅计算内容区域。

盒模型对比

CSS混合模式

mixBlendMode属性控制元素与其堆叠上下文中其他元素的颜色混合方式。各混合函数效果详见MDN文档

为提供更精细的混合控制,我们同时新增isolation属性。在View上设置isolation: isolate将强制创建堆叠上下文。可在祖先View设置此属性,确保带mixBlendMode的子代View不会超出隔离的 View 进行混合。

混合模式取值
  • normal:元素直接覆盖背景,无混合效果

  • multiply:源色与目标色相乘后替换目标

  • screen:对背景色与源色的补色相乘后取补色

  • overlay:根据背景色值进行乘色或滤色混合

  • darken:取背景色与源色的较暗值

  • lighten: 选择背景色和源颜色中较亮的一种

  • color-dodge:提亮背景色以映射源色(黑色绘制无变化)

  • color-burn:压暗背景色以映射源色(白色绘制无变化)

  • hard-light:根据源色值进行乘色或滤色(类似聚光灯照射效果)

  • soft-light:根据源色值加深或减淡颜色(类似柔光灯照射效果)

  • difference:从较亮色中减去较暗的组成色

  • exclusion:效果类似差值模式但对比度更低

  • hue:使用源色相的色调,并保留背景色的饱和度和亮度。

  • saturation:使用源色相的饱和度,并保留背景色的色调和亮度。

  • color:使用源色相的色调和饱和度,并保留背景色的亮度。此模式会保留背景的灰度层次,适用于单色图像着色或彩色图像色调调整。

  • luminosity:使用源色相的亮度,并保留背景色的色调和饱和度。此模式会产生与颜色模式相反的效果。

混合模式

轮廓属性

我们新增了 outlineWidthoutlineStyleoutlineSpreadoutlineColor 属性。这些轮廓属性的工作原理与对应的 border 属性类似,但关键区别在于轮廓是围绕边框盒(border box) 而非内边距盒(padding box) 绘制。这些属性可在不影响布局的前提下,通过描边突出显示元素。

更多细节请参阅 MDN 文档

轮廓属性

Android 15 支持与 16KB 页面支持

Android 15 强制无边显示

我们在之前的版本中已为 Android 15 支持做了准备工作。Android 15 最显著的变化是:当使用 targetSdk 35 构建应用时,系统会强制启用无边显示(edge-to-edge)。

若您尚未处理此变更,请参考我们之前的处理建议。忽略此变更可能导致应用界面异常。

备注

如果您在应用中使用 react-native-safe-area-context,该库已自动处理强制无边显示问题。

Android 16KB 页面大小支持

Android 15 引入了 16KB 内存页面支持,可为应用带来性能提升。但这也意味着基于 4KB 页面的旧应用在未来设备上可能出现兼容性问题。目前开发者可通过特定设备进行测试,为 16KB 页面成为系统默认配置做好准备。

通过 React Native 0.77 版本,开发者已可全面支持 16KB 页面大小,并能测试和发布适配 16KB 设备的应用。

更多关于 16KB 支持的信息,请参阅官方 Android 开发者文档

社区 CLI 与模板更新

社区 CLI:弃用 react-native init

此版本彻底完成了从 React Native 0.75 开始弃用 react-native init 命令的进程。

请注意,您将无法再使用 react-native init 命令,替代方案如下:

  • 使用框架(如 Expo),通过专属命令创建新项目:npx create-expo-app

  • 直接调用 Community CLI:npx @react-native-community/cli init

社区 CLI:从 Metro 移除"在 iOS/Android 运行"的按键处理程序

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

您可以在这篇专门文章中了解更多关于此变更的信息。

社区模板:Swift 成为 iOS 应用开发语言

信息

使用 Expo 的项目不受此变更影响。

此项变更让我们能够精简社区模板:用全新的 AppDelegate.swift 文件替代原有的三个文件(main.m, AppDelegate.hAppDelegate.mm)。

这属于破坏性变更:在升级助手工具中您将看到从 Objective-C 到 Swift 的变更,如下所示:

Swift 升级助手

您无需强制迁移到 Swift:Objective-C++ 版本的 iOS 社区模板仍受支持(请注意仍需集成 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 的每个调试环节都能可靠运行,并符合现代浏览器工具的功能标准。为实现这一质量目标,0.76 版本中已弃用的 Metro 日志转发功能,现已在 0.77 版本中移除。

该功能依赖自定义方法与设备上的调试目标通信。通过此项变更,我们将完全转向 Chrome DevTools 协议(CDP)。

  • 如需查看 JS 日志,请使用 React Native DevTools 及其功能完备的控制台面板——支持日志过滤、富对象检查、实时表达式等高级功能。

  • 您也可以通过第三方扩展(如 Expo ToolsRadon IDE)将 VS Code 作为 CDP 调试器连接。

    • 请注意这些集成方案未获得 React 团队的直接支持。但我们计划在 2025 年推出官方 VS Code 支持。
  • Expo CLI 仍继续提供日志流式传输功能。

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

其他破坏性变更

通用

  • 动画

    • 原生循环动画在每次循环结束时不再发送 React 状态更新
  • 布局

    • ScrollView 中粘性头部的 position 属性现在会被正确计算
    • 绝对定位现在以更符合规范的方式运行
  • JS 模块:

    • 移除 ReactFabricInternals 模块
      • 该模块将不再可访问
  • 原生模块

    • NativeModules 对象现在可用于在 JS 中加载 turbomodules
      • 这提高了原生模块与 Turbo 原生模块之间的兼容性
  • 包管理

    • dev-middleware:框架应指定相对于中间件主机的 serverBaseUrl
  • API 变更:

    • AppRegistry 中移除 useConcurrentRoot 类型(该类型已被忽略)
    • NativeMethods 的 TypeScript 定义中移除 refs 属性
  • 用户体验变更:

    • 从开发服务器快捷键命令中移除"在 iOS 上运行"和"在 Android 上运行"

Android 平台变更

  • Kotlin

    • 这是首个基于 Kotlin 2.0.21 构建的 React Native 版本。您可以在 Kotlin 发布说明中了解 Kotlin 2.0 的变更详情
  • API 变更:

    • 可空性:
      • ReadableArray 中的非原始类型 getter 现在被正确类型化为可选
      • ReactHost.createSurface() 方法设为非空
    • 重命名:
      • DevSupportManagerBase.getCurrentContext() 更名为 DevSupportManagerBase.getCurrentReactContext()

此外,多个 API 已被移除或限制可见性,无法再访问。这些 API 属于内部实现,React Native 开发者无需直接使用。完整列表如下:

List of Removed Android APIs:

The following packages are now internal and can’t be accessed anymore:

  • 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

The following classes are now either internal or have been removed, so can’t be accessed anymore:

  • BackHandler.removeEventListener
  • BaseViewManagerInterface
  • BindingImpl
  • CompositeReactPackage
  • DebugOverlayTags
  • Method create() from DefaultDevSupportManagerFactory
  • DevToolsReactPerfLogger
  • FabricComponents
  • ImageStoreManager
  • InteropModuleRegistry
  • NativeModulePerfLogger
  • NoopPrinter
  • NotThreadSafeViewHierarchyUpdateDebugListener
  • OkHttpCallUtil
  • PrinterHolder
  • Printer
  • ReactDebugOverlayTags
  • ReactNativeFlipper
  • ReactViewBackgroundManager
  • ReactViewGroup.getBackgroundColor()
  • ReactVirtualTextShadowNode
  • ReactVirtualTextViewManager
  • SimpleSettableFuture
  • SwipeRefreshLayoutManager
  • TaskCompletionSource
  • Parameter jsBundleLoader from DefaultReactHost.getDefaultReactHost()

iOS 平台变更

  • API 变更

    • 移除:
      • RCTConstants.RCTGetMemoryPressureUnloadLevel
      • partialBatchDidFlush
      • RCTRuntimeExecutor
      • UseNativeViewConfigsInBridgelessMode
        • 已由正式功能标志替代
      • UseTurboModuleInteropForAllTurboModules
        • Turbo 模块现已默认启用互操作层
    • 变更:
      • CGColorRef 的使用替换为 UIColor
  • RCTAppDelegate 现在要求使用 RCTDependencyProvider 加载第三方依赖

  • CocoaPods 为所有第三方依赖设置 C++ 版本以避免编译问题

React 19?

React 19 was released the 6th of December 2024. At the time, we already cut the branch for React Native 0.77 and we already released three RCs for React Native 0.77. It was too late in the release of React Native 0.77 to introduce React 19 in this release.

React 19 will be shipped in React Native 0.78, and we already cut the branch for this version. You can try it by creating a new app with the command:

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

致谢

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

特别感谢为本版本发布文档撰写功能说明的各位作者:

升级到 0.77 版本

对于现有项目,除了升级文档外,请使用 React Native Upgrade Helper 查看 React Native 各版本间的代码变更。

要创建新项目:

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

如果您使用 Expo,React Native 0.77 将在 Expo SDK 52 中得到支持(如何将 Expo 项目中的 React Native 更新至 0.77.0 的说明将在近期通过单独的 Expo 博客文章发布)。

信息

0.77 现已成为 React Native 的最新稳定版本,0.74.x 版本将不再获得支持。更多信息请参阅 React Native 支持政策。我们计划在近期为 0.74 版本发布最终的生命周期结束更新。