本文详解如何在 Ant Design 的 Select[mode="multiple"] 中动态显示用户选择顺序(如 Label-1、Label-2),并在标签(Tag)和下拉选项中同步更新序号,同时避免高频重渲染性能问题。
本文详解如何在 ant design 的 `select[mode="multiple"]` 中动态显示用户选择顺序(如 label-1、label-2),并在标签(tag)和下拉选项中同步更新序号,同时避免高频重渲染性能问题。
在 Ant Design 的多选组件中,默认仅维护选中值的集合(string[] 或 number[]),不保留选择时序信息。但实际业务中常需向用户明确传达“哪个先选、哪个后选”——例如配置字段优先级、构建有序筛选条件、或实现拖拽式排序的前置交互。直接修改 options 数组以动态拼接序号(如 "Label-1")虽可行,却会触发全量 options 重新计算与 Diff,显著降低大列表场景下的响应性能。
理想的解法是分离数据源与视图表达:用 useRef 缓存原始不可变选项(避免重复创建),用 useState 管理当前带序号的渲染态 options,并通过 tagRender 自定义选中标签,确保序号在关闭下拉时仍清晰可见。
以下是推荐实现方案(基于 Ant Design v5+):
import { Select, Tag } from 'antd';import React, { useState, useRef, useMemo } from 'react';type Option = { label: string; value: string };const OrderAwareMultiSelect = () => { // ✅ 原始选项 —— 用 useRef 静态持有,永不变更 const optionsRef = useRef<Option[]>([ { label: 'Label', value: '1' }, { label: 'Label', value: '2' }, { label: 'Label', value: '3' }, { label: 'Label', value: '4' }, ]); // ✅ 当前选中值序列(保持插入顺序) const selectedValuesRef = useRef<string[]>([]); // ✅ 渲染态 options:label 动态追加序号(如 "Label-1") const [renderOptions, setRenderOptions] = useState<Option[]>(optionsRef.current); // ? 核心逻辑:选中/取消时更新序号 const handleChange = (values: string[]) => { selectedValuesRef.current = values; // 仅对当前 options 做映射更新,避免深拷贝开销 setRenderOptions(prev => prev.map(opt => { const index = values.indexOf(opt.value); // 移除旧序号(支持 label 含下划线等场景),再追加新序号 const cleanLabel = opt.label.replace(/-d+$/, ''); return { ...opt, label: index === -1 ? cleanLabel : `${cleanLabel}-${index + 1}`, }; }) ); }; // ?️ 自定义 Tag 渲染:确保关闭面板时仍显示正确序号 const tagRender = ({ value, label, closable, onClose }: any) => { const option = optionsRef.current.find(o => o.value === value); const index = selectedValuesRef.current.indexOf(value); return ( <Tag onMouseDown={e => { e.preventDefault(); e.stopPropagation(); }} closable={closable} onClose={onClose} style={{ marginRight: 4 }} > {`${option?.label || label}-${index + 1}`} </Tag> ); }; return ( <Select mode="multiple" allowClear style={{ width: '100%' }} placeholder="请选择(序号反映选择顺序)" options={renderOptions} onChange={handleChange} tagRender={tagRender} // ⚠️ 关键:禁用默认 label 缓存,确保实时更新 showSearch={false} filterOption={false} /> );};export default OrderAwareMultiSelect;
该方案在保证交互直观性的同时,兼顾了性能与可维护性,是 Ant Design 多选序号化需求的生产就绪实践。