Skip to main content

第 32 章:Document Metadata 与资源预加载——title、style、preload

React 19 之前,改页面 <title> 得自己操作 document.title,引样式要手动塞 <link>,烦且容易乱。19 带来了两样东西:元数据提升(在组件里直接写 <title>/<meta>/<link>,React 帮你搬到 <head>)和资源预加载preload 系列提前拉关键资源)。

function ProfilePage() {
return (
<>
<title>我的主页</title>
<meta name="description" content="个人简介" />
<link rel="stylesheet" href="/profile.css" precedence="high" />
<ProfileContent />
</>
);
}

先记住这一句:元数据提升 = 你在任意组件里写 title/meta/link,React 把它提升到 <head>,同名去重、按 precedence 排顺序;预加载 = 用 preload/preinit 系列提前把关键资源拉起来,减少首屏等待。

一图流:元数据与预加载两条线

元数据提升:写在组件里,住在 head 里

以前 <title> 只能出现在 <head>,React 19 允许你在任意组件里写它。运行时(Float 系统,ReactDOMFloat)会把它识别为"可提升资源",从渲染位置搬到 <head>,并保证:

  • 去重:两个组件都写了 <title>,head 里只有一个;同名 <link> 同理。
  • 优先级:多个冲突资源(比如两个同名样式表),按 precedence 决定哪个生效、按什么顺序插入。
  • 服务端一致:SSR 时提升逻辑照跑,客户端水合后保持一致,不会闪 title。

样式表:从"手动管理"到"声明式"

<link rel="stylesheet" precedence="high"> 是 19 的关键新用法。以前你手动把 <link> 塞进 head、自己保证顺序;19 里你只需声明"这个样式表优先级多高",React 负责:

  1. 把它提升进 head。
  2. precedence 排序(相同优先级的按首次渲染顺序)。
  3. 样式表就绪前,用它包裹的内容先等它(避免 FOUC,样式闪变)。

这就是 precedence 的用途:让"后渲染的组件里引的样式"不会把"先渲染的样式"冲掉。

资源预加载:preload 系列

预加载 API 是一组"提前动手"的函数(都在 ReactDOMFloatReactDOMFloat.js:89):

API干什么源码
preconnect(58)提前建连接(DNS + TCP),给跨域资源省握手时间ReactDOMFloat.js:58
preload(89)提前拉资源进缓存,用时秒出(图片、字体、脚本)ReactDOMFloat.js:89
preloadModule(153)提前拉 ES moduleReactDOMFloat.js:153
preinit(205)提前执行(样式表、脚本),不等用就直接跑ReactDOMFloat.js:205

它们是给浏览器"提前热身"用的:你知道这个资源马上要用,但还没渲染到它,先 preload 拉起来,真正用时网络层已经就绪。对首屏性能,这是"把等待提前"的关键手段。

为什么值得单独讲

这两块在 19 之前的 React 里都不是一等公民:元数据要靠副作用手动改 document.head,资源要靠手写 <link> 或第三方库。19 把它们声明式化:告诉 React"这里有个 title、这个样式表优先级高、这个资源提前拉",剩下的提升、去重、排序、预加载,React 全包。这让页面级的东西第一次能"跟着组件走"。

动手实验

  1. 看提升:在组件深处写 <title>,渲染后查 document.head,确认 title 被提升到 head 且只有一个。
  2. 看 precedence:两个 precedence 不同的 <link> 样式表,查 head 里的插入顺序是否按优先级。
  3. 看 preload:在 preload(ReactDOMFloat.js:89)打断点,看它怎么给浏览器发"提前拉"的信号,Network 面板确认资源提前加载。

小结

  • 元数据提升:任意组件里写 title/meta/link → 自动搬到 head,去重、按 precedence 排顺序。
  • 样式表声明式管理:precedence 排序 + 就绪前防止样式闪变。
  • 预加载系列:preconnect(58) / preload(89) / preloadModule(153) / preinit(205),提前热身。
  • 19 把"页面级的东西"从副作用变成声明式,跟着组件走。
  • 下一步:19 到底删了什么、为什么删,第 33 章。