如果你做过服务端渲染(SSR,即在服务器上把组件渲染成 HTML 再发给浏览器),一定遇到过这种尴尬:某个组件里读了 localStorage、window 或设备时区,服务器上根本没有这些东西,渲染出来的 HTML 和浏览器第一次渲染的结果对不上,页面就会闪烁甚至报错。过去大家只能靠两种土办法:在 effect 里翻转一个 mounted 标志,或者用 typeof window !== 'undefined' 判断后再渲染。前者让首屏多一次无效渲染,后者则会在服务器和客户端首次渲染不一致时触发 hydration mismatch(水合不匹配,即浏览器接管页面时发现服务器给的 HTML 和自己算的不一样)。React 19.3 在 9 月 9 日发布,除了稳定的 View Transitions 和 Fragment Refs,还悄悄塞进了一个让社区期待已久的 API——react-dom 的 browser()。它的作用很直接:让一个组件正式声明"我只在浏览器里渲染",服务器端直接跳过它。用法出奇简单:在组件里调用 use(browser()),服务器渲染时这个组件会暂停,最近的 Suspense 边界(Suspense 是 React 用来处理异步渲染的机制,可以理解为"加载中"的占位)的 fallback 会出现在 HTML 里;而在浏览器端,browser() 返回 undefined,组件正常渲染。它必须从 Client Component(客户端组件,只在浏览器运行的组件)里调用,并且外面要包一层 Suspense,否则服务器渲染会直接报错。

这个 API 最妙的地方在于 use() 可以放在条件判断后面。比如一个数据请求 hook,如果 loader 已经提供了 initialData,就在服务器上正常渲染;否则就调用 use(browser()) 跳过服务器渲染,只在浏览器里请求数据。这被一位开发者评价为"我见过的对'这个请求到底该在服务器还是浏览器发'这个问题最干净的解决方案"。React 还加了一个 onBrowserBailout 回调和一个可选的 reason 参数,方便团队精确记录服务器渲染在哪个位置被跳过了。

这个设计其实是在缩小 React 与框架级逃生舱的差距。Next.js 用户早就习惯用 dynamic(() => import('./C'), { ssr: false }) 来禁用某个组件的服务器渲染,Astro 也有 client:only 指令,但这两个都绑死在各自的打包器上。browser() 把能力下沉到 React 本身,任何 SSR 方案都能用,不依赖具体框架。

升级方式就是标准的 [email protected] 和 [email protected],不过要注意 use 的参考文档里 browser() 还标注为 Canary(预发布通道)专用,生产环境使用前务必确认你的发布渠道。

这个 API 解决的是 SSR 场景里一个非常具体但高频的痛点。如果你在维护任何涉及 SSR 的 React 应用,尤其是那些需要读取浏览器专属 API 的组件(比如主题切换、时区显示、本地存储状态),browser() 值得立刻试试。它比 mounted 标志和 typeof window 判断都更语义化,也让"这个组件只在浏览器跑"这个意图在代码里一目了然。唯一的坑是它依赖 Suspense,如果你的组件树里没有现成的 Suspense 边界,需要先补一个。

Accelerating Performance by Incrementally Integrating Rust into Existing Codebas
Accelerating Performance by Incrementally Integrating Rust into Existing Codebas
阅读原文 → 返回 AI 技术文档

内容与图片版权归原作者所有 · 原文: https://www.infoq.com/news/2026/10/react-19-3-browser-api/?utm_campaign=infoq_content&utm_source=infoq&utm_medium=feed&utm_term=global