news 2026/6/22 4:13:19

【React + TypeScript 实现高性能多列多选组件】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【React + TypeScript 实现高性能多列多选组件】

引言

在现代Web应用中,多选组件是常见的UI元素,尤其是在需要用户从多个选项中进行选择的场景。本文将介绍如何使用React和TypeScript实现一个功能完整、性能优化的多列多选组件,支持"Select All"功能和垂直填充的多列布局。

组件功能介绍

本文实现的MultiCheck组件具有以下功能:

  1. 基础多选功能:支持用户选择多个选项
  2. "Select All"功能:一键全选/取消全选所有选项
  3. 多列布局:支持垂直填充的多列排列
  4. 受控组件设计:支持外部控制选中状态
  5. 性能优化:使用React Hooks优化渲染性能
  6. 类型安全:完整的TypeScript类型定义

技术栈

  • React 18:使用函数组件和Hooks
  • TypeScript:提供类型安全
  • CSS Grid:实现灵活的多列布局
  • React HooksuseState,useEffect,useCallback

核心实现

1. 类型定义

首先,我们定义组件的类型,确保类型安全:

exporttypeOption={label:string,value:string}typeProps={label?:string,options:Option[],columns?:number,values?:string[]onChange?:(options:Option[])=>void,}

2. 状态管理

使用useState钩子管理选中状态,并通过useEffect实现与外部状态的同步:

const[selectedValues,setSelectedValues]=useState<string[]>(values);// 监听外部values变化,实现双向更新useEffect(()=>{setSelectedValues(values);},[values]);

3. 全选功能实现

实现"Select All"功能需要以下逻辑:

// 判断是否全选constisAllSelected=options.length>0&&selectedValues.length===options.length;// 处理全选事件consthandleSelectAllChange=useCallback(()=>{constnewSelected=isAllSelected?[]:options.map(opt=>opt.value);setSelectedValues(newSelected);if(onChange){constselectedOptions=isAllSelected?[]:[...options];onChange(selectedOptions);}},[options,isAllSelected,onChange]);

4. 多列垂直填充布局

使用CSS Grid实现垂直填充的多列布局:

<div className='div-option-container'style={{display:'grid',gridTemplateColumns:`repeat(${Math.min(columns,options.length+1)}, auto)`,gridTemplateRows:`repeat(${Math.ceil((options.length+1)/columns)}, auto)`,gridAutoFlow:"column",// 关键:实现垂直填充width:'100%'}}>{/* 选项内容 */}</div>

5. 性能优化

使用useCallback缓存事件处理函数,避免不必要的重新渲染:

consthandleOptionChange=useCallback((value:string)=>{setSelectedValues(prev=>{constnewSelected=prev.includes(value)?prev.filter(v=>v!==value):[...prev,value];if(onChange){constselectedOptions=options.filter(opt=>newSelected.includes(opt.value));onChange(selectedOptions);}returnnewSelected;});},[options,onChange]);

完整组件代码

import'./MultiCheck.css';importReact,{useState,useEffect,useCallback}from'react';exporttypeOption={label:string,value:string}typeProps={label?:string,options:Option[],columns?:number,values?:string[]onChange?:(options:Option[])=>void,}constMultiCheck:React.FunctionComponent<Props>=({label,options,columns=1,values=[],onChange}):JSX.Element=>{const[selectedValues,setSelectedValues]=useState<string[]>(values);useEffect(()=>{setSelectedValues(values);},[values]);constisAllSelected=options.length>0&&selectedValues.length===options.length;consthandleSelectAllChange=useCallback(()=>{constnewSelected=isAllSelected?[]:options.map(opt=>opt.value);setSelectedValues(newSelected);if(onChange){constselectedOptions=isAllSelected?[]:[...options];onChange(selectedOptions);}},[options,isAllSelected,onChange]);consthandleOptionChange=useCallback((value:string)=>{setSelectedValues(prev=>{constnewSelected=prev.includes(value)?prev.filter(v=>v!==value):[...prev,value];if(onChange){constselectedOptions=options.filter(opt=>newSelected.includes(opt.value));onChange(selectedOptions);}returnnewSelected;});},[options,onChange]);return(<div className='div-container'style={{width:`${200*columns}px`}}>{label&&<div className='div-label-container'>{label}</div>}<div className='div-option-container'style={{display:'grid',gridTemplateColumns:`repeat(${Math.min(columns,options.length+1)}, auto)`,gridTemplateRows:`repeat(${Math.ceil((options.length+1)/columns)}, auto)`,gridAutoFlow:"column",width:'100%'}}><div className='div-option'><input type="checkbox"id="select-all"checked={isAllSelected}onChange={handleSelectAllChange}/><label htmlFor="select-all">Select All</label></div>{options.map(option=>(<div key={option.value}className='div-option'><input type="checkbox"id={`option-${option.value}`}checked={selectedValues.includes(option.value)}onChange={()=>handleOptionChange(option.value)}className='div-option-checkbox'/><label htmlFor={`option-${option.value}`}>{option.label}</label></div>))}</div></div>)}exportdefaultMultiCheck;

使用示例

importReactfrom'react';importMultiCheck,{Option}from'./MultiCheck';constApp:React.FC=()=>{constoptions:Option[]=[{label:'选项1',value:'1'},{label:'选项2',value:'2'},{label:'选项3',value:'3'},{label:'选项4',value:'4'},{label:'选项5',value:'5'},{label:'选项6',value:'6'},];consthandleChange=(selectedOptions:Option[])=>{console.log('选中的选项:',selectedOptions);};return(<div className="App"><MultiCheck label="多选组件示例"options={options}columns={2}values={['2','4']}onChange={handleChange}/></div>);};exportdefaultApp;

性能优化关键点

  1. 使用useCallback缓存事件处理函数:避免每次渲染都创建新函数
  2. 使用CSS Grid实现高效布局:减少JavaScript计算负担
  3. 合理设计依赖数组:确保Hooks只在必要时重新执行
  4. 函数式状态更新:避免闭包陷阱,确保基于最新状态更新

总结

本文实现的MultiCheck组件是一个功能完整、性能优化的多选组件,支持"Select All"功能和垂直填充的多列布局。通过使用React Hooks和TypeScript,我们实现了一个类型安全、性能优异的组件。

该组件的设计思路和实现方式可以作为开发其他复杂UI组件的参考,尤其是在需要处理大量选项和复杂布局的场景。

扩展建议

  1. 添加搜索功能:支持在大量选项中快速搜索
  2. 支持分组:实现选项的分组显示
  3. 添加键盘导航:提高可访问性
  4. 支持自定义样式:允许外部自定义组件样式
  5. 添加动画效果:提升用户体验

通过不断扩展和优化,这个组件可以适应更多复杂的业务场景,成为一个功能强大的多选组件库。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/18 8:16:03

Java毕设选题推荐:基于JavaWeb寝室管理系统基于Web的学生宿舍管理系统【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/20 2:50:29

华为MetaERP的成本优势主要体现在大幅削减直接费用、通过技术架构提升运营效率、以及规避长期风险与获取政策红利三大方面。这使其成为替代传统ERP(如Oracle、SAP)时,具备显著经济性的选择

华为MetaERP的成本优势主要体现在大幅削减直接费用、通过技术架构提升运营效率、以及规避长期风险与获取政策红利三大方面。这使其成为替代传统ERP&#xff08;如Oracle、SAP&#xff09;时&#xff0c;具备显著经济性的选择。下表直观对比了其主要成本优势点&#xff1a;优势维…

作者头像 李华
网站建设 2026/6/20 2:51:44

阿里拟析平头哥以赴市:论芯片分拆之战略深意

岁在丙午&#xff0c;正月廿二日&#xff0c;有西媒彭博传讯&#xff1a;阿里巴巴集团谋析其芯片子公司“平头哥”&#xff08;T-Head&#xff09;为独立之体&#xff0c;拟推之上市。闻者哗然&#xff0c;美股盘前应声而起&#xff0c;涨幅逾四。此非寻常之举&#xff0c;实乃…

作者头像 李华
网站建设 2026/6/20 3:53:59

科研AI模型复现难到崩溃?5个关键注意事项,一次复现成功!

点赞、关注、收藏。不迷路 做AI科研的兄弟姐妹们&#xff0c;谁没被模型复现折磨过&#xff1f; 照着顶刊论文逐行敲代码&#xff0c;却死活跑不出相同结果&#xff1b;作者给的参数模糊不清&#xff0c;调了几十组还是差好几个百分点精度&#xff1b;环境配置踩坑无数&#x…

作者头像 李华