diff --git a/src/TreeSelect.tsx b/src/TreeSelect.tsx index 75d88f8c..f2fbab58 100644 --- a/src/TreeSelect.tsx +++ b/src/TreeSelect.tsx @@ -412,9 +412,18 @@ const TreeSelect = React.forwardRef((props, ref) // Convert to value and filled with label const values = displayKeys.map(key => keyEntities[key]?.node?.[mergedFieldNames.value] ?? key); + // Avoid an O(displayed values × selected values) lookup + const labeledValueMap = new Map(); + rawLabeledValues.forEach(item => { + // Match `find` by keeping the first entry when controlled values contain duplicates. + if (!labeledValueMap.has(item.value)) { + labeledValueMap.set(item.value, item); + } + }); + // Back fill with origin label const labeledValues = values.map(val => { - const targetItem = rawLabeledValues.find(item => item.value === val); + const targetItem = labeledValueMap.get(val); const label = labelInValue ? targetItem?.label : treeTitleRender?.(targetItem); return { value: val, diff --git a/tests/Select.checkable.spec.tsx b/tests/Select.checkable.spec.tsx index 646c608d..685d18f4 100644 --- a/tests/Select.checkable.spec.tsx +++ b/tests/Select.checkable.spec.tsx @@ -531,6 +531,31 @@ describe('TreeSelect.checkable', () => { expect(getSelectionText(container, 0)).toEqual('0-0'); }); + it('preserves labels with SHOW_ALL', () => { + const { container } = render( + + + + + , + ); + + expect(getSelections(container)).toHaveLength(2); + expect([getSelectionText(container, 0), getSelectionText(container, 1)]).toEqual([ + 'First parent label', + 'Custom child', + ]); + }); + // https://github.com/ant-design/ant-design/issues/38126 it('keep label when not in options', () => { const onChange = jest.fn();