原文链接:www.epicreact.dev/use-react-a…
作者:Kent C. Dodds
您是否知道,当视频元素采用条件渲染时,其预加载属性 preload="auto" 将失效?React 的新组件 <Activity> 巧妙解决了这个问题。具体方法如下:
问题
假设你有一个包含预告片的电影目录。当用户点击"观看预告片"时,你希望播放视频,并希望预先加载视频以提升用户体验:
{
showTrailer ? <video src={movie.videoUrl} preload="auto" controls /> : null
}
问题在于:如果视频元素不在DOM中,浏览器就无法预加载它。因此当用户在网速较慢的环境下点击"观看预告片"时,仍需等待视频加载完成,这完全违背了预加载的初衷。
你可能会想:"那我直接用 display: none 之类的样式代替条件渲染不就行了!"这种方法或许可行,但其实还有更好的解决方案。
解决方案:Activity
React 19 的 <Activity> 组件正是为此而生。无需条件渲染视频,只需将其包裹在 Activity 边界中:
<Activity mode={showTrailer ? 'visible' : 'hidden'}>
<div className="overflow-hidden rounded-lg">
<video
src={movie.videoUrl}
title={movie.title}
loop
controls
preload="auto"
/>
</div>
</Activity>
现在视频元素始终存在于DOM中,因此 preload="auto" 确实有效!当用户在网速较慢时点击"观看预告片",视频会立即显示,因为它已在后台完成加载。
完整组件如下:
export function MovieTrailer({ movie }: { movie: Movie }) {
const [showTrailer, setShowTrailer] = useState(false)
useAutoplay(showTrailer)
return (
<div className="mb-6">
<button
onClick={() => setShowTrailer(!showTrailer)}
className="rr-button mb-4"
>
{showTrailer ? 'Hide Trailer' : 'Watch Trailer'}
</button>
<Activity mode={showTrailer ? 'visible' : 'hidden'}>
<div className="overflow-hidden rounded-lg">
<video
src={movie.videoUrl}
title={movie.title}
loop
controls
preload="auto"
/>
</div>
</Activity>
</div>
)
}
为什么是Activity?
Activity状态不仅能通过 display: none 实现隐藏/显示。当隐藏时,它会:
- 视觉上隐藏子元素
- 清理效果(暂停订阅等操作)
- 保留组件状态以便再次显示时恢复
- 允许 DOM 继续存在(因此预加载功能正常工作!)
这使其成为需要用户再次交互的内容的理想选择,例如标签页、模态框,或像我们案例中需要预加载的视频。
处理视频字段播放
由于使用Activity时视频始终存在于DOM中,因此需谨慎处理自动播放功能。以下是一个自定义钩子,用于在视频隐藏时暂停播放:
function useAutoplay(showTrailer: boolean) {
useEffect(() => {
const video = document.querySelector('video')
if (!(video instanceof HTMLVideoElement)) return
if (!showTrailer) {
void video.pause()
return
}
video.volume = 1
void video.play()
return () => {
void video.pause()
}
}, [showTrailer])
}
这确保视频在隐藏时暂停,在显示时播放,让您两全其美:既能预加载内容,又能实现精准的播放控制。
了解更多
Activity 是 React 19 中一个强大的新组件,其应用场景远不止视频预加载。查阅 React 文档了解:
- 隐藏组件时的状态恢复
- DOM 状态的保留(如表单输入)
- 提升 hydration 性能
- 以及更多功能!
Activity 完美展现了 React 解决实际问题的实力。快在你的下个项目中尝试吧!