Skip to content

Commit e87efd4

Browse files
authored
chore: optimize multiple onChange performence(#22822) (#501)
1 parent 6822d0f commit e87efd4

File tree

2 files changed

+45
-7
lines changed

2 files changed

+45
-7
lines changed

src/generate.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import useLayoutEffect from './hooks/useLayoutEffect';
4040
import { getSeparatedContent } from './utils/valueUtil';
4141
import useSelectTriggerControl from './hooks/useSelectTriggerControl';
4242
import useCacheDisplayValue from './hooks/useCacheDisplayValue';
43+
import useCacheOptions from './hooks/useCacheOptions';
4344

4445
const DEFAULT_OMIT_PROPS = [
4546
'removeIcon',
@@ -419,6 +420,8 @@ export default function generateSelector<
419420
[mergedOptions],
420421
);
421422

423+
const getValueOption = useCacheOptions(mergedRawValue, mergedFlattenOptions);
424+
422425
// Display options for OptionList
423426
const displayOptions = React.useMemo<OptionsType>(() => {
424427
if (!mergedSearchValue || !mergedShowSearch) {
@@ -454,16 +457,17 @@ export default function generateSelector<
454457
let displayValues = React.useMemo<DisplayLabelValueType[]>(
455458
() =>
456459
mergedRawValue.map((val: RawValueType) => {
460+
const valueOptions = getValueOption([val]);
457461
const displayValue = getLabeledValue(val, {
458-
options: mergedFlattenOptions,
462+
options: valueOptions,
459463
prevValue: baseValue,
460464
labelInValue: mergedLabelInValue,
461465
optionLabelProp: mergedOptionLabelProp,
462466
});
463467

464468
return {
465469
...displayValue,
466-
disabled: isValueDisabled(val, mergedFlattenOptions),
470+
disabled: isValueDisabled(val, valueOptions),
467471
};
468472
}),
469473
[baseValue, mergedOptions],
@@ -473,13 +477,14 @@ export default function generateSelector<
473477
displayValues = useCacheDisplayValue(displayValues);
474478

475479
const triggerSelect = (newValue: RawValueType, isSelect: boolean, source: SelectSource) => {
476-
const outOption = findValueOption([newValue], mergedFlattenOptions)[0];
480+
const newValueOption = getValueOption([newValue]);
481+
const outOption = findValueOption([newValue], newValueOption)[0];
477482

478483
if (!internalProps.skipTriggerSelect) {
479484
// Skip trigger `onSelect` or `onDeselect` if configured
480485
const selectValue = (mergedLabelInValue
481486
? getLabeledValue(newValue, {
482-
options: mergedFlattenOptions,
487+
options: newValueOption,
483488
prevValue: baseValue,
484489
labelInValue: mergedLabelInValue,
485490
optionLabelProp: mergedOptionLabelProp,
@@ -507,10 +512,10 @@ export default function generateSelector<
507512
if (useInternalProps && internalProps.skipTriggerChange) {
508513
return;
509514
}
510-
515+
const newRawValuesOptions = getValueOption(newRawValues);
511516
const outValues = toOuterValues<FlattenOptionsType<OptionsType>>(Array.from(newRawValues), {
512517
labelInValue: mergedLabelInValue,
513-
options: mergedFlattenOptions,
518+
options: newRawValuesOptions,
514519
getLabeledValue,
515520
prevValue: baseValue,
516521
optionLabelProp: mergedOptionLabelProp,
@@ -519,7 +524,7 @@ export default function generateSelector<
519524
const outValue: ValueType = (isMultiple ? outValues : outValues[0]) as ValueType;
520525
// Skip trigger if prev & current value is both empty
521526
if (onChange && (mergedRawValue.length !== 0 || outValues.length !== 0)) {
522-
const outOptions = findValueOption(newRawValues, mergedFlattenOptions);
527+
const outOptions = findValueOption(newRawValues, newRawValuesOptions);
523528

524529
onChange(outValue, isMultiple ? outOptions : outOptions[0]);
525530
}

src/hooks/useCacheOptions.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import * as React from 'react';
2+
import { RawValueType, FlattenOptionsType, Key } from '../interface/generator';
3+
4+
export default function useCacheOptions<
5+
OptionsType extends {
6+
value?: RawValueType;
7+
label?: React.ReactNode;
8+
key?: Key;
9+
disabled?: boolean;
10+
}[]
11+
>(values: RawValueType[], options: FlattenOptionsType<OptionsType>) {
12+
const prevOptionMapRef = React.useRef<Map<RawValueType, FlattenOptionsType<OptionsType>[number]>>(
13+
null,
14+
);
15+
16+
const optionMap = React.useMemo(() => {
17+
const map: Map<RawValueType, FlattenOptionsType<OptionsType>[number]> = new Map();
18+
options.forEach(item => {
19+
const {
20+
data: { value },
21+
} = item;
22+
map.set(value, item);
23+
});
24+
return map;
25+
}, [values, options]);
26+
27+
prevOptionMapRef.current = optionMap;
28+
29+
const getValueOption = (vals: RawValueType[]): FlattenOptionsType<OptionsType> =>
30+
vals.map(value => prevOptionMapRef.current.get(value)).filter(Boolean);
31+
32+
return getValueOption;
33+
}

0 commit comments

Comments
 (0)