发布时间:2026/9/5 16:36:03
shadcn Radix → Base UI 迁移中的调用点改造指南:Consumer-Side Prop 变更清单与排查流程 shadcn Radix → Base UI 迁移中的调用点改造指南Consumer-Side Prop 变更清单与排查流程【免费下载链接】uiA set of beautifully-designed, accessible components and a code distribution platform. Works with your favorite frameworks. Open Source. Open Code.项目地址: https://gitcode.com/GitHub_Trending/ui/ui本文聚焦 consumer-props.md 这份迁移参考资料在 Radix 到 Base UIbase-ui/react迁移中shadcn 组件包装器的导出名保持不变但业务代码**调用点call sites**上的 props 会发生变更或直接消失。读完本篇你将掌握一份逐组件的 props 改造清单含回调签名规则、asChild→render的通用替换模式以及一套可执行的“grep 排查 → 逐文件修复 → FLAG 行为差异”标准流程并能结合本仓库的双注册表源码验证每个映射。1. 为什么调用点需要单独一步迁移工作分为两层组件包装器components/ui下的 shadcn wrapper和业务代码wrapper 的消费者。SKILL.md 的迁移策略说明中指出包装器可以通过 CLI 的“golden pair”机制自动化交付 Base UI 变体但Consumer/app code has no CLI mechanism: always hand-migrate it againstconsumer-props.md.也就是说应用代码没有 CLI 机制只能对照本文的清单手工迁移。这正是 consumer-props.md 存在的意义它列出的是“wrapper 名不变、但调用处 props 必须改”的完整清单全部条目均经过base-ui/react1.6.0类型定义的核对文档明确给出核验原则——拿不准时去查node_modules/base-ui/react/**/*.d.ts永远不要猜。本仓库也维护着可对照验证的“地面真相”apps/v4/registry/bases 下并排存在base/Base UI 支撑与radix/Radix 支撑两套注册表universal-patterns.md声明的知识库即来自对apps/v4/registry/bases/{radix,base}/ui/中 61 组组件对的机械 diff。迁移时可以用同一组件的两套包装器源码互相印证本文表格。2. 通用规则asChild→render文档中的 Universal 一节只有一条但它是调用点改造中出现频率最高的一条RadixBase UI调用点动作asChild任意 wrapperrenderpropTrigger asChildButton//Trigger→Trigger render{Button/}...Radix 的asChild是布尔标志把 props 合并到唯一子元素上Base UI 的render直接接收要渲染的元素。本仓库 Base 变体包装器中随处可见这一模式例如 dialog.tsx 的关闭按钮DialogPrimitive.Close render{Button variantoutline /}alert-dialog.tsx 同样以render{Button variant{variant} size{size} /}取代了 Radix 时代的asChild。因此排查时对所有组件统一执行grepasChild逐个替换为render配合 universal-patterns.md 中的 Slot 手动惯用法改写规则非按钮多态组件改用useRendermergeProps如 breadcrumb.tsx 所示。3. 逐组件 props 变更清单以下表格完整继承 consumer-props.md 的 Per component 清单按组件族分组并补充仓库内可验证的实现证据。3.1 表单控件Accordion、Checkbox、Slider、Select、ToggleGroup组件Radix propBase UI 去向调用点动作Accordiontypesingle\|multiplecollapsible移除value/defaultValue永远是数组多开通过multipletypesingle collapsible→ 两者都删值包成数组typemultiple→multipleCheckboxcheckedindeterminateindeterminate是独立的布尔 propcheckedindeterminate→indeterminate 布尔checkedSlideronValueChange(value)签名获得事件详情参数另外inverted被移除检查 handler 形参个数删除inverted若有 vertical-inverted 用法需 FLAGSlideronValueCommitonValueCommitted重命名Selectpositionpopper\|item-alignedalignItemWithTrigger布尔量位于 Positioner 上wrapper 已暴露positionpopper→alignItemWithTrigger{false}item-aligned→alignItemWithTrigger默认值SelectonValueChange(value: string)加宽为(value: Value \| null, eventDetails)useStatestringonValueChange{setState}会编译失败把 state 加宽为string \| null或包一层 setterToggleGrouptypesingle\|multiplemultiple布尔量value 形状为数组与 Accordion 同样处理Accordion 的“值永远是数组”不是文字游戏本仓库的 Base 示例直接体现了这一点——accordion-basic.tsx 中写的是defaultValue{[item-1]}而 Radix 版本对应的是标量。同时注意 Base 包装器中AccordionContent实际渲染的是AccordionPrimitive.Panel见 accordion.tsx即 Radix 的Content部件在 Base 中改名为Panel但shadcn 包装器导出名仍是AccordionContent调用点不需要改名只需处理 props。Select 的onValueChange加宽是最容易在 typecheck 中爆雷的一条如果应用里写const [value, setValue] useStatestring(...)然后onValueChange{setValue}迁移后setValue不接受null直接编译失败。修法有两种——把 state 类型改为string \| null或包一层(v: string \| null) setValue(v ?? )。3.2 反馈与浮层Tooltip、Dialog 家族、Popover/HoverCard组件Radix propBase UI 去向调用点动作TooltipProviderdelayDuration、skipDelayDurationdelayskip-delay 概念被移除重命名 / 删除TooltipdisableHoverableContent无等价物删除在迁移报告中 FLAG 行为变化Popover / HoverCardRoot 上的openDelay/closeDelay移到TRIGGER上名为delay/closeDelay把 props 从 Root 搬到 TriggerDialog / AlertDialogonOpenAutoFocusinitialFocus基于元素/ref而非事件重构传目标而不是 preventDefault 回调Dialog / AlertDialogonCloseAutoFocusfinalFocus同样重构Dialog 家族onEscapeKeyDown、onPointerDownOutside、onInteractOutside已合并精确的逐部件签名见 overlays 参考查 overlays.md不要猜overlays.md 对最后一行给出了可直接落地的细节Radix 的逐交互回调onEscapeKeyDown/onPointerDownOutside/onFocusOutside/onInteractOutside在 Base UI 中没有一一对应的 prop统一由onOpenChange的第二个参数eventDetails承接——判断eventDetails.reasonescape-key、outside-press、focus-out再调用eventDetails.cancel()来阻止关闭等价于 Radix 的event.preventDefault()。而onOpenAutoFocus/onCloseAutoFocus则改到 Popup 部件的initialFocus/finalFocus接受boolean \| RefObject \| (openType) ...三种形态所以调用点从“事件处理器”变成“焦点目标”的重构。3.3 导航类Tabs、Menubar、ContextMenu、NavigationMenu、Toolbar组件Radix propBase UI 去向调用点动作TabsactivationModemanual移除Base UI 默认就是手动激活删除 prop近似替代是Tabs.List activateOnFocus行为有差异FLAG不要自动添加Menubarvalue/onValueChange活动菜单移除改为逐个Menu.Root用open控制若有用到需重构通常没人用MenubarlooploopFocus重命名ToggleGroup / ToolbarrovingFocus{false}移除roving focus 恒开loop→loopFocus删除 / 重命名ContextMenu.Rootmodal移除删除ContextMenu.Triggerdisabled移除删除触发器禁用改由自己控制DropdownMenu/ContextMenu 菜单项Radix 选中即关闭菜单closeOnClick在 CheckboxItem/RadioItem 上默认 FALSE行为差异FLAG仅在用户要求时添加closeOnClickNavigationMenudelayDuration(200)、skipDelayDuration、viewportdelay(50) closeDelayviewport prop 消失由 Positioner 承担重命名/删除FLAG 200→50 的悬停延迟手感变化注意这张表里有两条是行为差异而非编译错误closeOnClick默认 false 意味着“点击复选/单选菜单项后菜单不自动关闭”Radix 下则会关闭Tabs 默认手动激活意味着点击 tab 不再自动切换面板。SKILL.md 的 Hard rules 明确规定行为差异一律 FLAG、绝不静默修补目标是产出“与 shadcn base registry 一致的惯用 Base UI”。3.4 其余零散项组件Radix propBase UI 去向调用点动作Avatar.ImagedelayMsdelay重命名ScrollAreatypealways\|scroll\|...移除删除Separatordecorative移除删除DirectionProviderdirdirection重命名4. 回调签名规则Callback Signature Rule文档单列一节说明回调签名的一般规律Base UI 的回调普遍新增一个 event-details 参数onOpenChange(open, eventDetails) onValueChange(value, eventDetails)由此推出两条实操结论已有的单参 handler 保持不变、依然类型安全TS 允许传参更少的函数曾经使用 Radix 事件参数的 handleronValueChange(value, event)这种必须对照对应组件族的参考文件逐一复查。第 3.1 节 Select 的加宽就是这一规则的反例提醒参数个数不变但类型变宽string→string | nulltypecheck 仍会失败不能依赖“单参函数天然兼容”这一点。5. 标准排查流程Sweep Procedure文档给出三步流程配合 SKILL.md 的整体迁移纪律使用grep 应用代码components/ui之外的部分逐个搜索上表左列的每个 token 外加asChild逐文件修复调用点每修完一个文件立即 typecheck不要攒批量提交把报错定位到文件粒度凡是在清单中被标记FLAG的项Tabs 手动激活、菜单项不点击关闭、NavigationMenu 50ms 延迟、TooltipdisableHoverableContent无等价物、Sliderinverted等一律写入迁移报告作为行为差异behavior delta绝不静默修补。报告落在项目根目录的.migration/component.md每个组件一个文件结构固定为Changed/Left alone/Behavior changes/Verify by hand四节见 SKILL.md 的 Verify and report 一节。渐进式迁移时这一步对应 SKILL.md 流程中的“repoint consumers ONE AT A TIMEimports the call-site props inconsumer-props.mdtypecheck each”——调用点改造是消费者切换到新 wrapper 导入时同步完成的那半份工作。6. 映射的验证方式以类型定义为准以仓库双注册表为旁证文档强调“when in doubt, checknode_modules/base-ui/react/**/*.d.ts, never guess”。在本仓库内还有两条独立的验证路径双注册表 diffapps/v4/registry/bases 中radix/与base/两套包装器逐文件对照。例如 Base 版 accordion.tsx 使用AccordionPrimitive.Item的value数组语义与data-starting-style/ending-style动画钩子而 Radix 版对应typesingle与data-[stateopen]——两套文件并排阅读即可复核第 3.1 节的每一条。示例代码apps/v4/examples/base/ 提供的是迁移后的“目标态”调用方式可直接作为调用点改造的参照实现。需要说明的适用前提本文清单基于base-ui/react1.6.0的类型定义核对文档首行注明若升级 Base UI 版本个别 prop 名称或默认值可能变化应以新版本的.d.ts为准重新过一遍这份清单。7. 小结调用点改造是 Radix → Base UI 迁移中“CLI 帮不上忙”的部分包装器可以自动化交付但asChild、type/collapsible、position、delayDuration、onOpenAutoFocus这一类 props 只能在业务代码里逐个替换。本文的清单给出了一张可直接 grep 的对照表、一条asChild → render的通用规则、一条回调签名规则以及“grep → 逐文件 typecheck → FLAG 行为差异”的可执行流程配合仓库内radix/与base/双注册表源码可以在迁移每个组件后对映射做二次验证确保应用代码在保留原有行为意图的前提下切换到 Base UI 语义。【免费下载链接】uiA set of beautifully-designed, accessible components and a code distribution platform. Works with your favorite frameworks. Open Source. Open Code.项目地址: https://gitcode.com/GitHub_Trending/ui/ui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

2026/9/5 16:31:03

Qwerty Learner:10分钟上手的免费英语打字训练工具

Qwerty Learner:10分钟上手的免费英语打字训练工具 【免费下载链接】qwerty-learner 为键盘工作者设计的单词记忆与英语肌肉记忆锻炼软件 / Words learning and English muscle memory training software designed for keyboard workers 项目地址: https://gitcod…

2026/9/5 17:31:05

Cesium圆绘制工具:从Ellipse原理到动态交互实现

在 Cesium 项目里,“圆”可能是我见过开发频率最高的图元之一。很多业务场景都会先画一个半径范围:雷达扫描范围、风电场影响圈、安全警戒区、通勤圈、地块覆盖范围等。最初我习惯把圆心和半径写成常量,直接塞进一个 ellipse ,但…

2026/9/5 17:31:05

从写代码到说需求:vivo广告小游戏AI辅助开发全解析

在vivo开放平台投广告小游戏,最直观的感受就是:以前我写的是if (player.score > 100) { levelUp(); },现在我写的是“帮我加一个逻辑,玩家分数超过100就升级,并且弹个窗提示他获得新技能”。这不是段子,…

2026/9/5 17:31:05

从反射到强类型:FUI路由的Source Generator演进

从 GetTypes() 到强类型 Route:FUI Source Generator 的设计演进先交代一下背景。FUI 是我们内部的一个跨端 UI 框架,核心模块之一就是路由。早期版本的路由注册走的是最典型的反射方案:程序启动时扫描程序集,拿到所有标记了 Rout…

2026/9/5 17:26:05

AI游戏开发实战:NVIDIA ACE与生成式引擎的落地组合

2026年聊AI游戏开发,已经没有多少人还在纠结“要不要接入AI”了,大家默认一件事:AI跟渲染管线、物理引擎一样,是立项阶段就要想清楚的底层能力。我最近大半年几乎把NVIDIA ACE和Summer Engine这两类代表工具翻了个底朝天&#xff…

2026/9/5 2:46:54

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/9/5 2:46:52

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/5 2:44:34

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/5 0:04:47

流式背压机制:避免前端渲染卡死与内存暴涨的滑动窗口限流

流式背压机制:避免前端渲染卡死与内存暴涨的滑动窗口限流在大模型流式输出(Streaming)与智能体实时推流的架构中,生产环境中经常出现一种“上下游生产消费速率严重失衡”的极端情况: 生产端极速产出:大模型…

2026/9/5 2:45:13

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/5 2:30:42

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/5 2:46:50

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…