UI组件前端【免费下载链接】ariakitToolkit with accessible components, styles, and examples for your next web app项目地址https://gitcode.com/gh_mirrors/ar/ariakit点击查看免费下载本文基于 Ariakit 仓库中的 combobox-filtering-integrated 示例 展开讲解如何通过一个抽象化的Combobox封装结合 React 并发特性React.useDeferredValue与match-sorter库实现输入即过滤的下拉搜索组件。读完本文你将掌握如何把value/onChange受控接口映射到useComboboxStore的inputValue/setInputValue如何用useStoreState高效读取 store 状态以及如何通过 React Context 让ComboboxItem按搜索结果动态挂载/卸载。示例总览官方示例的定位是在 Combobox 组件中通过一个抽象化实现React.useDeferredValue对选项进行过滤从而得到一个更简洁的高层 API。与手动把过滤结果数组传给组件的传统写法不同本示例中使用者只需要把全部条目渲染为ComboboxItem过滤、匹配、空状态全部由封装组件内部处理。最终的使用方式非常干净见 示例入口文件import { Combobox, ComboboxEmpty, ComboboxItem } from ./combobox.tsx; export default function Example() { return ( Combobox autoSelect placeholderSearch food ComboboxEmptyNo results found/ComboboxEmpty ComboboxItem valueApple / ComboboxItem valueBacon / ComboboxItem valueBanana / ComboboxItem valueBroccoli / ComboboxItem valueBurger / {/* ... 共 38 个食品条目 */} ComboboxItem valueYogurt / /Combobox ); }注意几个细节autoSelect打开时自动聚焦首个条目提升键盘操作体验条目是静态写死在 JSX 里的没有任何list.map(...)这是集成过滤写法的核心卖点ComboboxEmpty用于在没有匹配项时显示空状态文案。受控接口把value/onChange映射到useComboboxStore抽象组件的完整实现位于 combobox.tsx。它的 props 定义刻意模仿了 HTML 输入框的受控约定export interface ComboboxProps extends OmitAriakit.ComboboxProps, onChange { value?: Ariakit.ComboboxProviderProps[inputValue]; onChange?: Ariakit.ComboboxProviderProps[setInputValue]; children?: React.ReactNode; }这里value对应 store 的inputValue状态onChange对应setInputValue状态 setter。封装时直接把这两个自定义 props 透传给底层 store 钩子export const Combobox React.forwardRefHTMLInputElement, ComboboxProps( function Combobox({ value, onChange, children, ...props }, ref) { const [list, setList] React.useStatestring[]([]); const combobox Ariakit.useComboboxStore({ inputValue: value, // 受控外部传入当前搜索值 setInputValue: onChange, // 状态变更时回调外部 onChange }); const searchValue Ariakit.useStoreState(combobox, inputValue); // ... }, );这正是 Ariakit Component stores 指南 中描述的受控状态模式把不带default/set前缀的精确状态属性传给 storestore 就不会在内部维护该状态而是只调用你提供的 setter。由此得到两个好处组件可以像原生受控输入框一样被父组件驱动Combobox value{v} onChange{setV} /也可以不传value而以非受控方式使用——store 内部会自行维护inputValue过滤逻辑需要的当前搜索值通过useStoreState读取无论受控与否都能拿到一致的当前值const searchValue Ariakit.useStoreState(combobox, inputValue);从源码结构看useStoreState是 Ariakit 提供的通用状态订阅钩子实现位于 ariakit-react-store 包支持整包订阅 / 指定键订阅 / selector 订阅三种模式只订阅inputValue这一个键意味着组件仅在搜索值变化时才因该值重渲染属于指南中推荐的Watching a specific state property用法。用useDeferredValuematch-sorter计算匹配结果拿到searchValue后示例并没有直接用它做过滤而是先经过一层延迟值// 延迟值可以避免输入时的卡顿源码注释原文Use deferred value to avoid lag when typing const deferredValue React.useDeferredValue(searchValue); // matchSorter 每次渲染都跑可能开销较大因此做记忆化 const matches React.useMemo(() { return matchSorter(list, deferredValue); }, [list, deferredValue]);这里的分工非常清晰React.useDeferredValue把过滤计算这类低优先级更新从高频的按键输入中解耦出来。用户输入时输入框本身的更新高优先级不会被阻塞过滤结果可以在稍后的低优先级更新中追上来从而保持输入流畅matchSorter(list, deferredValue)对已注册的条目列表做模糊匹配match-sorter由示例源码直接import { matchSorter } from match-sorter引入useMemo只有list或deferredValue变化时才重新计算避免每次无关渲染都执行匹配。计算出的matches匹配到的字符串数组连同setList一起打包成 React Context 下发const contextValue React.useMemo(() ({ matches, setList }), [matches]);Context 的定义与类型const ComboboxContext React.createContext{ matches?: string[]; setList?: React.DispatchReact.SetStateActionstring[]; }({});动态渲染ComboboxItem挂载即注册失配即卸载ComboboxItem的抽象是整个示例最核心的部分源码见 combobox.tsxexport const ComboboxItem React.forwardRefHTMLDivElement, ComboboxItemProps( function ComboboxItem({ value, ...props }, ref) { const { matches, setList } React.useContext(ComboboxContext); // 挂载时把条目加入 list卸载时移除源码注释原文 React.useLayoutEffect(() { if (!setList) return; if (value null) return; setList((list) [...list, value]); return () { setList((list) list.filter((v) v ! value)); }; }, [setList, value]); const match value ! null matches?.includes(value); // 条目不在匹配列表中就不渲染 if (!match) return null; return ( Ariakit.ComboboxItem ref{ref} focusOnHover blurOnHoverEnd{false} {...props} value{value} className{clsx(combobox-item, props.className)} / ); }, );拆开看有三个关键机制条目自注册self-registration每个ComboboxItem通过useLayoutEffect在挂载时把自己的value追加进父组件的list状态在卸载清理函数中移除。list因此始终与当前渲染中的条目保持同步——父组件完全不需要手动维护选项数组。选择useLayoutEffect而非useEffect是为了在浏览器绘制前完成注册避免首帧匹配列表缺项条件渲染即过滤matches.includes(value)为 false 时直接return null。也就是说过滤效果是靠条目组件自行决定渲染与否达成的DOM 中永远只有命中的条目。这与非集成版示例 combobox-filtering 的写法形成对照——后者是显式地matches.map((value) ComboboxItem key{value} value{value} /)由父级计算并传入结果数组交互行为配置条目统一带上focusOnHover悬停即聚焦与blurOnHoverEnd{false}悬停结束时不主动移除焦点保证鼠标与键盘焦点行为一致。一个重要的顺序限制需要特别理解这种条件渲染式的过滤无法改变条目的显示顺序——被过滤后的条目始终保持原始列表中的顺序。原因从源码即可看出ComboboxItem只判断matches.includes(value)成员关系从不读取该条目在matches中的索引或排序位置而 DOM 顺序由 JSX 中条目的书写顺序决定。如果你希望过滤后保持原始顺序比如菜单按固定分组/权限排列这个方案非常合适如果你依赖matchSorter的相关性排序匹配度高的排前面则此写法不满足需求应改用非集成写法直接对matches数组做map渲染让匹配结果的顺序驱动渲染顺序。ComboboxEmpty基于匹配计数的空状态空状态组件同样消费 Context逻辑极简combobox.tsxexport const ComboboxEmpty React.forwardRefHTMLDivElement, ComboboxEmptyProps( function ComboboxEmpty(props, ref) { const { matches } React.useContext(ComboboxContext); // 只要有匹配项就完全不渲染 if (matches?.length) return null; return ( Ariakit.Role ref{ref} {...props} className{clsx(no-results, props.className)} / ); }, );它渲染的是Ariakit.Role一个不带内置行为、只用于承载样式与结构语义的基座组件在matches为空数组时显示 children示例中为 No results found。样式由 style.css 提供该文件通过import复用 combobox-filtering 的样式其中.no-results类附加了间距与内边距。弹出层配置ComboboxPopover的实用参数封装组件把输入框与弹出层一并返回ComboboxPopover上配置了几个值得注意的参数combobox.tsx参数作用store{combobox}将输入框与弹出层接入同一个 store建立类似aria-controls的部件关联portal将弹出层渲染到 portal 中避免被父级overflow裁剪sameWidth弹出层宽度与输入框保持一致gutter{8}弹出层与锚点元素之间保留 8px 间距unmountOnHide隐藏时卸载弹出层子树注意条目卸载后useLayoutEffect清理函数会把值移出list再次打开时会重新注册children被包裹在ComboboxContext.Provider内再交给弹出层这保证了ComboboxItem/ComboboxEmpty即使不显式接收storeprop也能通过 Context 拿到matches与setList。与非集成版combobox-filtering的对照仓库中同系列的 combobox-filtering 示例 是显式过滤写法两者构成一组递进关系维度combobox-filtering显式combobox-filtering-integrated集成状态控制ComboboxProvider的setValue回调内部用React.startTransition包裹setSearchValueuseComboboxStore的inputValue/setInputValue对外暴露受控value/onChange防卡顿手段React.startTransition把过滤状态更新标记为可中断的过渡更新React.useDeferredValue延迟搜索值再配合useMemo记忆化匹配结果条目渲染matches.map((value) ComboboxItem ... /)顺序由匹配结果决定可利用排序静态写死全部ComboboxItem value... /靠条件渲染过滤顺序固定为原始顺序使用者心智需要维护list、matches与渲染映射只需声明条目过滤逻辑完全内聚在封装组件中两种写法的过滤算法都可以自由替换官方文档提到除match-sorter外还可以选用采用模糊搜索算法的fast-fuzzy等库Combobox组件本身对过滤策略是无关的agnostic——它只关心你通过ComboboxItem渲染出的条目。小结与相关示例本文覆盖的 combobox-filtering-integrated 示例提供了三层可复用的经验API 抽象层用Omit..., onChange 自定义value/onChangeprops把内部 store 细节藏起来对外保持熟悉的受控组件契约并发过滤层useDeferredValueuseMemo保证高频输入下 UI 不卡顿条目自治层ComboboxItem自注册 条件渲染配合 Context 中的matches实现声明式过滤与空状态。需要留意顺序限制过滤不改变条目顺序这一设计权衡按需选择本示例或显式映射写法。以下相关示例可继续深入 Combobox 的其他能力均为仓库内路径combobox-filtering显式过滤 startTransitioncombobox-animated带动画的下拉combobox-cancel可取消的过滤输入combobox-multiple多选标签式 Comboboxcombobox-tabs与 Tabs 组合的导航型 Comboboxdialog-combobox-tab-command-menuDialog Combobox CommandMenu 复合弹窗menu-nested-combobox嵌套菜单中的 Combobox更多设计原理可参考仓库内文档Combobox 组件说明 与 Component stores 指南。赞分享UI组件前端【免费下载链接】ariakitToolkit with accessible components, styles, and examples for your next web app项目地址https://gitcode.com/gh_mirrors/ar/ariakit点击查看免费下载相关推荐Sapphire框架49最佳实践10个提升Discord机器人性能的技巧Sapphire框架49最佳实践10个提升Discord机器人性能的技巧 Sapphire框架49是基于discord.js构建的高级Discord机器人框架Cycle.js响应式搜索过滤组件构建可复用的高级搜索组件Cycle.js响应式搜索过滤组件构建可复用的高级搜索组件 你是否在开发搜索功能时遇到过用户输入卡顿、下拉菜单闪烁或结果更新不及时的问题Cycle.js的响前端Web框架coss Combobox 实战指南在 Kaneo 中构建可搜索选择组件coss Combobox 实战指南在 Kaneo 中构建可搜索选择组件 导读 Combobox组合框是可搜索选择的 UI 原语它把文本输入与列表选择合企业应用后端前端上一篇opsu!游戏机制解析圆圈、滑条和转盘的操作技巧下一篇MaterialFiles深度剖析Android平台最强Material Design文件管理器横空出世创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
转子动力学前沿与ANSYS仿真:从临界转速到故障机理 简介:《转子动力学前沿研究》汇集了第十一届IFToMM国际转子动力学会议的最新成果,面向机械工程、动力学与控制领域的科研人员、工程师及高校师生。内容围绕转子系统建模、轴承动态性能、振动控制与故障诊断展开,具体涉及角接触球轴承刚度计算… · 2026/9/25 3:38:50
OctoPrint JS 客户端库 Socket 模块完全指南:SockJS 实时通信、消息订阅与通信节流机制 物联网后端 【免费下载链接】OctoPrint OctoPrint is the snappy web interface for your 3D printer! 项目地址: https://gitcode.com/gh_mirrors/oc/OctoPrint 点击查看 免费下载 本文围绕 OctoPrint JavaScript Client Library 中的 OctoPrintClient.socket 组件… · 2026/9/25 3:38:50
2024年网络安全人才报告解读:薪资四档、人才缺口与AI冲击 简介:《2024年网络安全产业人才发展报告》是一份全面解析网络安全人才市场的行业调研资料,适合政府决策者、企业管理者、教育机构、网络安全从业者及高校学生参考,帮助各方把握人才供需现状、薪酬水平与AI技术带来的变革。压缩包内为PDF格式&… · 2026/9/25 7:19:08
视频专网系统安全技术方案:从边界防护到计算加固的实战指南 简介:视频专网系统安全是安防工程与网络建设中不可忽视的环节,该PDF资料围绕视频专网面临的前端入侵、网络滥用、数据泄露等风险,给出了从安全体系设计到分域防护建设的完整思路,面向系统集成、安防工程和网络运维人员。内容共分三… · 2026/9/25 7:19:01
HW高危漏洞自查:21个必修漏洞的排查与修复实战指南 简介:《2024HW必修高危漏洞集合-v4.0》是斗象情报中心面向企业安全团队与HW攻防演练参与者整理的高危漏洞自查手册,聚焦2023年1月至7月攻防演练中红队利用率高、对企业危害较大的漏洞类型,涵盖远程代码执行、命令注入、任意文件上传与SQL注入… · 2026/9/25 7:19:01
buildah rm 命令详解:删除构建容器的工作原理、参数与实战用法 云原生 【免费下载链接】buildah A tool that facilitates building OCI images. 项目地址: https://gitcode.com/gh_mirrors/bu/buildah 点击查看 免费下载 Buildah 是一个专注于构建 OCI 镜像的命令行工具,其核心工作流围绕"工作容器"&… · 2026/9/25 7:19:01
CTF-All-In-One实战解读:从基础到PWN漏洞利用的系统路线 简介:《ctf-all-in-one.pdf》是一本系统完整的CTF(Capture The Flag)学习手册,定位为从零基础到进阶的一站式参考,适合网络安全爱好者、高校学生及竞赛选手。文档首先介绍CTF历史、比赛形式与规则,随后分模… · 2026/9/25 7:19:01
AI Agent工作流重构:从Prompt到可审计任务闭环 1. 这不是“又一个AI概念”,而是工作流重构的临界点“AI agent”这个词最近在技术圈和创业圈里炸开了锅,但很多人一听到就下意识觉得是“大模型套壳”“智能体玄学”“又一个炒作名词”。我从2022年就开始在真实业务中落地agent类系统——最早是给一家医… · 2026/9/25 7:18:55
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37