- 前端
- UI组件
【免费下载链接】primitives
Radix Primitives is an open-source UI component library for building high-quality, accessible design systems and web apps. Maintained by @workos.
@radix-ui/react-use-layout-effect是 Radix Primitives 组件库内部使用的基础工具 Hook,核心解决一个高频问题:在服务端渲染(SSR)与 React Server Components(RSC)环境下,直接调用 React 的useLayoutEffect会触发控制台警告。本文以该包的 CHANGELOG 版本演进为骨架,结合仓库源码深入解析其实现原理、RSC 兼容性保障、CI 发布机制与真实使用场景,帮助读者理解 Radix 这类 UI 库如何安全地在 SSR 环境中复用布局副作用逻辑。
包定位:仅供内部使用的工具包
该包的 README.md 只有一句话:"This is an internal utility, not intended for public usage."(这是一个内部工具,不面向公开使用)。与@radix-ui/react-dialog、@radix-ui/react-tooltip这类面向最终用户的组件不同,react-use-layout-effect被设计为 Radix 各组件共享的底层基础设施,通过 internal.ts 统一导出后供内部模块引用:
export { useLayoutEffect } from '@radix-ui/react-use-layout-effect';从 package.json 可以看到它的完整元信息:
- 名称:
@radix-ui/react-use-layout-effect - 当前版本:
1.1.4 - 许可证:MIT
sideEffects: false:声明无副作用,便于打包器(webpack/rollup)进行 tree-shaking 优化- peerDependencies:
react ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc,并声明@types/react为可选依赖 - 脚本:
lint(oxlint)、typecheck(tsc --noEmit)、build(radix-build)、clean/reset
核心实现:一行代码的 SSR 安全判断
该包的全部实现只有约 11 行,位于 use-layout-effect.tsx:
import * as React from 'react'; /** * On the server, React emits a warning when calling `useLayoutEffect`. * This is because neither `useLayoutEffect` nor `useEffect` run on the server. * We use this safe version which suppresses the warning by replacing it with a noop on the server. * * See: https://reactjs.org/docs/hooks-reference.html#uselayouteffect */ const useLayoutEffect = globalThis?.document ? React.useLayoutEffect : () => {}; export { useLayoutEffect };实现思路极为精炼,其逻辑可拆解为三步:
- 环境探测:通过
globalThis?.document判断当前是否运行在浏览器环境。存在document对象即意味着客户端渲染上下文,否则为服务端(Node.js)或 RSC 渲染环境。 - 客户端分支:浏览器环境直接透传 React 原生的
useLayoutEffect,保留其在 DOM 变更后同步执行副作用的全部特性。 - 服务端分支:用一个空函数
() => {}替换。因为在服务端无论useLayoutEffect还是useEffect都不会真正执行,直接替换为空实现既消除了 React 的警告,又避免了不必要的逻辑挂载。
入口文件 index.ts 仅做一层转发:
export { useLayoutEffect } from './use-layout-effect';注意:代码注释中解释了服务端触发警告的根因——React 在服务端不会运行任何 effect(包括
useLayoutEffect与useEffect),因此直接调用会收到 "useLayoutEffect does nothing on the server" 之类的提示。该工具通过环境判断在源头规避了这一警告。
为什么需要它:SSR/RSC 下的useLayoutEffect警告
React 的 Hooks 参考文档 明确指出useLayoutEffect只在浏览器端有意义:它会在 DOM 变更之后、浏览器绘制之前同步刷新布局副作用,常用于测量元素尺寸、同步更新 DOM 位置等需要避免闪烁的场景。
问题在于:
- 服务端渲染阶段根本没有 DOM,
useLayoutEffect无法执行; - 直接调用时 React 会在控制台输出警告,干扰日志排查;
- 在 React Server Components 模型中,模块顶层若引用了客户端专属 API,还可能引发导入错误(详见下文 RSC 兼容性章节)。
Radix 的解法不是封装复杂的环境判断工具函数,而是将"浏览器环境检查"与"原生 hook 引用"固化在一个常量上,既保证运行时零开销,又让所有内部组件获得一致的、无警告的 SSR 体验。
版本演进主线:从元数据补全到 RSC 兼容性回滚
该包 CHANGELOG.md 记录了三个版本的关键变更,构成了本文分析的主线:
1.1.2:补充repository.directory元数据
Added repository.directory to all package.json files
该版本为所有 package.json 增加了repository.directory字段。以本包为例,package.json 中记录了仓库类型、URL 与目录:
"repository": { "type": "git", "url": "git+https://github.com/radix-ui/primitives.git", "directory": "packages/react/use-layout-effect" }这一字段是 npm 生态的通用约定:monorepo 中的包通过它指明自身在仓库中的子目录位置,方便工具链(如npm、依赖机器人、缺陷追踪插件)正确跳转到源码所在路径,是包元数据规范化的基础性工作。
1.1.3:通过 CI 重新发布以附加 provenance 认证
Republish through CI to attach provenance attestations. The previous versions of these packages were published manually outside of CI and therefore shipped without provenance; this patch re-releases the same code through the CI pipeline so every package includes an attestation.
该版本是一次纯发布流程变更,不涉及任何代码改动。其技术要点:
- provenance(来源证明)是 npm 供应链安全机制,通过发布时生成的签名证明(attestation)向安装方声明"该包由声明的来源构建并发布",可有效缓解依赖混淆与供应链投毒风险;
- 此前版本是脱离 CI 手动发布,因而缺失 provenance;
- 本次通过 CI 流水线重新发布相同代码,使所有包含的包都附带认证。
从仓库实际发布流程看,这也体现了该 monorepo 将发布固化为 CI 环节的整体策略——与 release-process.md 中描述的发布流程相互印证。
1.1.4:回滚破坏性变更,修复 RSC 兼容性
Reverted breaking changes that caused compatibility issues with React Server Components.
这是当前最新版本,也是最具技术深度的一条:
- 上一版中引入了某类破坏性变更(breaking changes),导致包在 React Server Components 环境下出现兼容性问题;
- 1.1.4 将其回滚,恢复为与 RSC 兼容的行为;
- 结合 use-layout-effect.tsx 的当前实现可见,
globalThis?.document的空值安全写法(?.)本身即是面向 RSC 的设计——在服务端globalThis.document为undefined,可选链保证了访问不抛错,从而让模块在 Server Component 中可安全导入。
RSC 兼容性的仓库级保障:测试与脚手架
1.1.4 的兼容性回滚并非孤立行为,仓库对此有系统性保障。根目录的 scripts/rsc-compatibility.rsc.test.ts 是专门的 RSC 回归防护测试,其核心设计:
- 运行环境:该测试套件在 React 的
react-server构建下运行(对应vitest.config.mts中的rsc项目),此构建中客户端专属 API 为undefined,用以模拟 Server Component 的模块上下文; - 校验点:测试断言
React.createContext为undefined,确保确实跑在 React 的 server build 上,避免"测试通过了但测错环境"; - 边界机制:声明了
"use client"的包被视为客户端边界会被桩替换(stub),未声明的包则要求能被 Server Component 直接导入且不抛错; - 覆盖范围:遍历
core与react两个包组中所有可发布的包,逐一验证其入口模块可被安全导入。
该测试的注释还明确指出:模块顶层(module scope)的客户端专属引用是导入期即可捕获的问题,而仅在渲染期调用的客户端 API 无法在导入时被发现——这正是@radix-ui/react-use-layout-effect采用"常量级环境判断"方案的深层原因:把客户端专属的React.useLayoutEffect引用收敛到条件分支中,避免它在模块顶层对 RSC 导入产生副作用。
仓库还提供 apps/ssr-testing 这一 Next.js SSR 测试应用(含 rsc 页面),用于在真实服务端渲染场景中验证各组件与 Hook 的兼容性。
真实使用场景:遍布 Radix 组件内部的底层依赖
useLayoutEffect在 Radix 组件库中被广泛引用,是众多交互组件的公共地基。仓库内的使用证据包括:
- id.tsx:生成确定性 ID 的核心逻辑。对于 React 18 之前的版本,通过
useLayoutEffect在客户端为无deterministicId的调用生成递增的radix-${id}ID:useLayoutEffect(() => { if (!deterministicId) setId((reactId) => reactId ?? String(count++)); }, [deterministicId]); - announce.tsx:无障碍"实时区域"(aria-live)通知组件,依赖该 Hook 同步执行文本变更后的播报逻辑;
- avatar.tsx:镜像图片加载状态到 ref,并同步触发
onLoadingStatusChange回调;同时负责通过new window.Image()预加载图片并在useLayoutEffect中挂载 load/error 事件监听; - use-effect-event.tsx:在 React 尚未稳定提供
useEffectEvent时,用useLayoutEffect将最新回调写入 ref 以近似模拟其行为; - 此外,dialog.tsx、popper.tsx、popover.tsx、navigation-menu.tsx、portal.tsx、collapsible.tsx、scroll-area.tsx、slider.tsx、toast.tsx、tooltip.tsx、roving-focus-group.tsx 等均引入了该 Hook,用于在布局阶段同步完成焦点管理、位置计算、尺寸测量等操作。
这种"一个底层 Hook 服务数十个组件"的架构,正是 Radix 将 SSR 安全的副作用处理固化为单一内部包的原因:任何组件都不需要重复实现环境判断,且所有组件共享同一份经过 RSC 测试验证的实现。
总结
从 1.1.2 的元数据规范,到 1.1.3 的 CI 发布与 provenance 认证,再到 1.1.4 的 RSC 兼容性回滚,@radix-ui/react-use-layout-effect的版本演进完整展示了 Radix 对 SSR/RSC 兼容性的持续投入。其核心价值在于:
- 实现极简:以
globalThis?.document的常量级判断替代运行时复杂逻辑,服务端分支降级为空函数,从源头消除useLayoutEffect的服务端警告; - 兼容面广:peerDependencies 覆盖 React 16.8 至 19 的全部主流版本;
- 生态保障:与
scripts/rsc-compatibility.rsc.test.ts、apps/ssr-testing等仓库设施配合,形成从单元测试到真实 SSR 应用的多层验证体系。
对希望在自有 SSR/RSC 应用中安全使用useLayoutEffect的开发者而言,这个包的实现与版本故事是一个可直接借鉴的范本:用一次环境探测,换取所有组件与页面在服务端渲染时的零警告、零异常。
- 前端
- UI组件
【免费下载链接】primitives
Radix Primitives is an open-source UI component library for building high-quality, accessible design systems and web apps. Maintained by @workos.
相关推荐
Osmedeus Cloud Cheatsheet:多云端分布式扫描的完整速查与源码级解析
Osmedeus Cloud Cheatsheet:多云端分布式扫描的完整速查与源码级解析 本篇速查指南聚焦 Osmedeus( GitHub_Trending
前端UI组件Reka UI 完全指南:以可访问性与无样式理念构建 Vue 设计系统的现代组件库
Reka UI 完全指南:以可访问性与无样式理念构建 Vue 设计系统的现代组件库 本篇技术指南以 Reka UI(Radix Vue v2 演化版)官方 In
前端UI组件@radix-ui/react-compose-refs 深入解析:Radix Primitives 中 ref 组合工具的实现原理与版本演进
@radix ui/react compose refs 深入解析:Radix Primitives 中 ref 组合工具的实现原理与版本演进 导读 @radi
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考