深入探讨 React 的新 <Activity> 组件
Source: Dev.to
介绍
你是否曾在应用中切换标签页后返回时,发现滚动位置丢失、输入框内容被清空,或者又看到加载中的旋转图标?
传统上,React 开发者通过有条件地挂载或卸载组件来实现“显示与隐藏” UI:
{isShowingSidebar && <Sidebar />}
虽然这种方式有效,但每次卸载都会销毁组件的状态。在现代 React(v19+)中,有更好的办法。那就是 <Offscreen> 组件。
在实验阶段它被称为 “Offscreen” API,<Offscreen> 是一个内置的 React 组件,允许你在不丢失内部状态或 DOM 节点的情况下隐藏并恢复 UI。它不是把元素从树中移除,而是让它们在后台“保持活跃”,只是视觉上隐藏。
基本语法
import { Offscreen } from 'react';
import { useState } from 'react';
function App() {
const [isVisible, setIsVisible] = useState(true);
return (
<Offscreen mode={isVisible ? "visible" : "hidden"}>
{/* Your component tree */}
</Offscreen>
);
}
保留“短暂”状态
<Offscreen> 不仅保留 JavaScript 状态,还会保留 DOM 状态。
- 表单草稿 – 如果用户在表单中输入内容后切换标签页再回来,文字仍然在。
- 滚动位置 – 不再需要手动的“滚动恢复”逻辑——因为元素从未被移除,浏览器会自然保持滚动位置。
智能预渲染
<Offscreen mode="hidden">
{/* Heavy component that can be pre‑rendered */}
</Offscreen>
当组件位于隐藏的 <Offscreen> 边界内时:
- React 以更低的优先级渲染它,确保不会阻塞主线程。
- 它可以获取数据(如果使用了支持 Suspense 的数据源,如
use)。 useEffect会被跳过,直到组件真正可见时才执行。
更快的首次 Hydration
与 display: none 有何不同?
虽然 <Offscreen> 在内部确实使用 display: none 来隐藏元素,但它加入了多层“React 智能”:
- 副作用编排 – 当
mode="hidden"时,React 会销毁你的useEffect清理函数,并仅在组件变为可见时重新运行。这防止后台组件运行计时器或订阅,从而消耗资源。 - 优先级管理 – 隐藏的
<Offscreen>内的更新会被降级。React 不会让后台重新渲染导致前台 UI 帧率下降。 - 视图过渡 – 它与 View Transition API 集成,在内容进入或退出时提供平滑动画。
- ref 行为 – 由于 DOM 节点仍然存在,ref 仍然指向隐藏的元素。
- 仅文本组件 – 如果组件仅返回文本(没有包装元素),隐藏时
<Offscreen>不会渲染任何东西,因为没有 DOM 元素可以应用display: none。 - 副作用 – 不在
useEffect中的副作用(例如自动播放的<video>)可能会在后台继续运行。请确保你的组件“行为良好”。
何时使用 <Offscreen>
<Offscreen> 组件是迈向“自主” UI 的重要一步——应用可以在后台准备内容,并准确记住用户离开的状态。如果你正在构建:
- 复杂的仪表盘
- 多标签页界面
- 性能密集的 Web 应用
是时候停止卸载,改用 <Offscreen> 了。
你计划将标签页重构为使用 <Offscreen> 吗?在评论中告诉我吧!