9:23Better Stack
Log in to leave a comment
No posts yet
技术的寿命比我们想象的要短。过去几年统治 React 生态系统的 Radix UI 就是一个典型的例子。截至 2026 年,Radix UI Primitives 仓库的提交频率已降至每周平均不到 0.5 次。它实际上已处于“僵尸状态”。与此同时,由其核心架构师加入 MUI 团队后打造的 Base UI,每天都会发布超过 25 次更新。这不仅仅是流行趋势的问题,更是关乎生存的选择。
过去,我们对 Radix 的 asChild 模式推崇备至。但在实际开发中,这个模式却成了麻烦。由于它在内部使用 cloneElement,经常导致 Props 冲突,且 TypeScript 的类型推断始终不稳定。
Base UI 通过 Render Props 模式正面解决了这一问题。这不仅是语法的改变,更通过减少运行时开销优化了性能,并让开发者能够 100% 控制传递给子元素的 Props。
在 Base UI 中,组件的内部状态可以直接作为渲染函数的参数获取。不需要像 Radix 那样笨拙地连接外部 Hook。
cloneElement,选择了直接的函数调用方式。从 2026 年开始实施的 欧洲无障碍法案 (EAA) 和 WCAG 2.2 标准现在已成为必选项而非加分项。Base UI 在服务端渲染 (SSR) 环境中能保持一致的 ARIA 属性。这防止了 Hydration 过程中的布局偏移 (Layout Shift),并大幅提升了首次交互时间 (TTI)。
在企业级环境中,最痛苦的任务莫过于实现多选 (Multi-select) 或组合框 (Combobox)。Radix 缺乏这类高性能组件,导致我们总得打上一堆外部库的“补丁”。
Base UI 原生支持多选功能。特别是与 @tanstack/react-virtual 等虚拟化库的结合非常顺滑。在处理大规模数据时,它的价值尤为凸显。
Base UI 的 Function as ClassName 模式在配合 Tailwind CSS 时最为强大。你可以声明式地管理样式,而不是使用复杂的多元运算符。
typescript <Select.Item className={(state) =>
flex items-center px-4 py-2 rounded-lg
${state.highlighted ? 'bg-indigo-50 text-indigo-900' : 'text-slate-700'}
${state.selected ? 'font-semibold bg-indigo-100' : 'font-normal'}
${state.disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
`}
{item.label}
</Select.Item>
`
一次性推翻所有代码是自杀行为。你需要一种渐进且战略性的方法。
阶段 1:共存期
在保留现有 Radix UI 的同时,并行安装 npm install @base-ui-components/react。
阶段 2:新功能优先采用
在新增的模态框或复杂表单中率先引入 Base UI。为团队成员留出熟悉 Render Props 模式的时间。
阶段 3:核心设计系统替换
仅替换设计系统中公共组件的内部实现为 Base UI。只要保持外部 API 接口不变,就能在不触动其他团队代码的情况下实现底层架构的现代化。
| 比较项目 | Radix UI | Base UI |
|---|---|---|
| 核心机制 | cloneElement Props 注入 | Render Props 函数调用 |
| Props 控制权 | 低(库主导) | 高(开发者直接传递) |
| 状态访问 | 需要外部 Hook | 作为渲染函数参数立即注入 |
| 维护状态 | 实际上已停止 (截至 2026 年) | 非常活跃 (MUI 团队主导) |
shadcn/ui 的最新更新已经开始采用 Base UI 作为基础原子组件。市场的领导权已经完全转移。技术债务拖得越久,利息就越高。Radix UI 曾带来的创新,现在已进化为 Base UI 这种完成度更高的形态。
可维护性和对无障碍标准的遵循是 2026 年前端开发者的核心竞争力。是时候切换到更清晰、更注重性能的工具了。2026 年的项目,不应再停留于昨天的遗产中。