Skip to content

Commit

Permalink
Select: Performance improvements when opening menu and when hovering …
Browse files Browse the repository at this point in the history
…over options (#69230)
  • Loading branch information
JoaoSilvaGrafana authored and LudoVio committed Jun 26, 2023
1 parent fee4dff commit 1be3639
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 4 deletions.
12 changes: 9 additions & 3 deletions packages/grafana-ui/src/components/Select/SelectBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { SingleValue } from './SingleValue';
import { ValueContainer } from './ValueContainer';
import { getSelectStyles } from './getSelectStyles';
import { useCustomSelectStyles } from './resetSelectStyles';
import { ActionMeta, SelectBaseProps } from './types';
import { ActionMeta, InputActionMeta, SelectBaseProps } from './types';
import { cleanValue, findSelectedValue, omitDescriptions } from './utils';

interface ExtraValuesIndicatorProps {
Expand Down Expand Up @@ -155,6 +155,7 @@ export function SelectBase<T>({
const reactSelectRef = useRef<{ controlRef: HTMLElement }>(null);
const [closeToBottom, setCloseToBottom] = useState<boolean>(false);
const selectStyles = useCustomSelectStyles(theme, width);
const [hasInputValue, setHasInputValue] = useState<boolean>(!!inputValue);

// Infer the menu position for asynchronously loaded options. menuPlacement="auto" doesn't work when the menu is
// automatically opened when the component is created (it happens in SegmentSelect by setting menuIsOpen={true}).
Expand Down Expand Up @@ -224,7 +225,9 @@ export function SelectBase<T>({
defaultValue,
// Also passing disabled, as this is the new Select API, and I want to use this prop instead of react-select's one
disabled,
filterOption,
// react-select always tries to filter the options even at first menu open, which is a problem for performance
// in large lists. So we set it to not try to filter the options if there is no input value.
filterOption: hasInputValue ? filterOption : null,
getOptionLabel,
getOptionValue,
hideSelectedOptions,
Expand All @@ -250,7 +253,10 @@ export function SelectBase<T>({
menuShouldScrollIntoView: false,
onBlur,
onChange: onChangeWithEmpty,
onInputChange,
onInputChange: (val: string, actionMeta: InputActionMeta) => {
setHasInputValue(!!val);
onInputChange?.(val, actionMeta);
},
onKeyDown,
onMenuClose: onCloseMenu,
onMenuOpen: onOpenMenu,
Expand Down
6 changes: 5 additions & 1 deletion packages/grafana-ui/src/components/Select/SelectMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ export const SelectMenuOptions = ({
const theme = useTheme2();
const styles = getSelectStyles(theme);
const icon = data.icon ? toIconName(data.icon) : undefined;
// We are removing onMouseMove and onMouseOver from innerProps because they cause the whole
// list to re-render everytime the user hovers over an option. This is a performance issue.
// See https://github.com/JedWatson/react-select/issues/3128#issuecomment-451936743
const { onMouseMove, onMouseOver, ...rest } = innerProps;

return (
<div
Expand All @@ -109,7 +113,7 @@ export const SelectMenuOptions = ({
isSelected && styles.optionSelected,
data.isDisabled && styles.optionDisabled
)}
{...innerProps}
{...rest}
aria-label="Select option"
title={data.title}
>
Expand Down

0 comments on commit 1be3639

Please sign in to comment.