简体   繁体   English

单击外部时反应选择不会关闭

[英]react-select wont close when clicking outside

I'm using react-select and have made a few customizations to it.我正在使用 react-select 并对其进行了一些自定义。 I tried to modify the ValueContainer and the SelectContainer components which cause some issues.我试图修改导致一些问题的 ValueContainer 和 SelectContainer 组件。 The dropdown wont close when I click outside of it after having selected a value.选择一个值后,当我在下拉菜单外部单击时,下拉菜单不会关闭。 I'm wondering if anyone can see what I have done wrong here?我想知道是否有人能看到我在这里做错了什么?

I'm assuming that the dropdown wont close because the onBlur event for the Input doesn't trigger.我假设下拉菜单不会关闭,因为 Input 的 onBlur 事件不会触发。 Eg the input doesn't regain its focus after i click a value with closeMenuOnSelect = true.例如,在我单击具有closeMenuOnSelect = true 的值后,输入没有重新获得焦点。 I am also assuming that this is because react-select cant find the input for some reason because I've modified the structure.我还假设这是因为 react-select 由于某种原因无法找到输入,因为我已经修改了结构。 Might be missing some refs or something but I can't understand where to get them and where to put them.可能缺少一些参考或其他东西,但我不明白从哪里得到它们以及把它们放在哪里。 Anyone know?有人知道吗?

Here is my custom Select component:这是我的自定义 Select 组件:

const ReactSelect: React.FC<ReactSelectProps> = ({
  backgroundColor,
  isSearchable = false,
  placeholder = '',
  size,
  grow,
  className,
  required,
  label,
  variant = 'underline',
  dataTestId,
  ...props
}) => {
  const filterConfig = {
    ignoreCase: true,
    ignoreAccents: true,
    matchFromStart: false,
    stringify: (option: any) => `${option.label}`,
    trim: true,
  };

  const [showIsRequired, setShowIsRequired] = useState(
    !props.defaultValue && required
  );

  const handleOnChange = (newValue: any, actionMeta: ActionMeta<any>) => {
    setShowIsRequired(!newValue && required);
    if (props.onChange) {
      props.onChange(newValue, actionMeta);
    }
  };

  const properties = {
    ...props,
    className: className,
    onChange: handleOnChange,
    isSearchable: isSearchable,
    styles: customStyles(size, backgroundColor, grow, showIsRequired, variant),
    menuPlacement: 'auto' as MenuPlacement,
    placeholder: placeholder,
    noOptionsMessage: () => t`Ingen elementer funnet`,
    loadingMessage: () => t`Laster...`,
    filterOption: createFilter(filterConfig),
    closeMenuOnSelect: !props.isMulti,
    hideSelectedOptions: false,
    components: {
      ValueContainer: (inputProps: ValueContainerProps) => (
        <ValueContainer required={required} label={label} {...inputProps} />
      ),
      Option,
      SelectContainer: (containerProps: ContainerProps) => (
        <SelectContainer dataTestId={dataTestId} {...containerProps} />
      ),
    },
  };

  if ('value' in props) {
    return <StateManagedSelect {...properties} />;
  }

  return <Select {...properties} />;
};

And here are my custom <SelectContainer> and <ValueContainer> :这是我的自定义<SelectContainer><ValueContainer>

const ValueContainer = ({ children, label, required, ...rest }: any) => {
  const labelFloatingStyle = {
    top: '0.30rem',
    left: '0.6rem',
    transform: 'translate(0, 0) scale(1)',
    fontSize: '0.75rem',
    color: 'hsl(236, 91%, 9%)',
    fontWeight: '500',
  };
  const labelStyle = {
    top: '50%',
    left: '0.75rem',
    transform: 'translate(0, -50%) scale(1)',
    fontSize: '1rem',
    color: 'hsl(0, 0%, 45%)',
  };
  const requiredDotStyles = {
    color: 'hsl(35, 100%, 43%)',
    fontSize: '1.5rem',
    display: rest.hasValue ? 'none' : 'inline',
  };
  const getLabelStyles = () =>
    rest.hasValue || rest.isFocused ? labelFloatingStyle : labelStyle;
  return (
    <components.ValueContainer {...rest}>
      {children}
      {label && (
        <label
          style={{
            position: 'absolute',
            transformOrigin: 'left bottom',
            transition: 'all 0.2s',
            display: 'flex',
            alignItems: 'center',
            ...getLabelStyles(),
          }}
        >
          {label} {required && <span style={requiredDotStyles}>*</span>}
        </label>
      )}
    </components.ValueContainer>
  );
};

const SelectContainer = ({ dataTestId, ...rest }: any) => (
  <div data-test-id={dataTestId}>
    <components.SelectContainer {...rest} />
  </div>
);

The problem was with how I sendt in the custom components.问题在于我如何发送自定义组件。 You shouldn't pass the props there.你不应该在那里传递道具。 I think that might ruin some of the important ReactSelect props like refs and such.我认为这可能会破坏一些重要的 ReactSelect 道具,例如 refs 等。

Send the components in like this instead.改为像这样发送组件。 Define your custom properties in this object as well:在此 object 中定义您的自定义属性:

  const properties = {
    ...props,
    className: className,
    onChange: handleOnChange,
    isSearchable: isSearchable,
    styles: customStyles(size, backgroundColor, grow, showIsRequired, variant),
    menuPlacement: 'auto' as MenuPlacement,
    placeholder: placeholder,
    noOptionsMessage: () => t`Ingen elementer funnet`,
    loadingMessage: () => t`Laster...`,
    filterOption: createFilter(filterConfig),
    closeMenuOnSelect: !props.isMulti,
    hideSelectedOptions: false,
    label: label,
    required: required,
    dataTestId: dataTestId,
    components: {
      ValueContainer,
      Option,
      SelectContainer,
    },
  };

  if ('value' in props) {
    return <StateManagedSelect {...properties} />;
  }

  return <Select {...properties} />;

Then you can get these custom props in the custom component using props.selectProps like this:然后你可以使用props.selectProps在自定义组件中获取这些自定义道具,如下所示:

const ValueContainer = ({ children, ...rest }: any) => {
  const { label, required } = rest.selectProps; // HERE
  const labelFloatingStyle = {
    top: '0.20rem',
    left: '0.6rem',
    transform: 'translate(0, 0) scale(1)',
    fontSize: '0.75rem',
    color: 'hsl(236, 91%, 9%)',
    fontWeight: '500',
  };
  const labelStyle = {
    top: '50%',
    left: '0.75rem',
    transform: 'translate(0, -50%) scale(1)',
    fontSize: '1rem',
    color: 'hsl(0, 0%, 45%)',
  };
  const requiredDotStyles = {
    color: 'hsl(35, 100%, 43%)',
    fontSize: '1.5rem',
    display: rest.hasValue ? 'none' : 'inline',
  };

  const getLabelStyles = () =>
    rest.hasValue || rest.isFocused ? labelFloatingStyle : labelStyle;

  return (
    <components.ValueContainer {...rest}>
      {children}
      {label && (
        <label
          style={{
            position: 'absolute',
            transformOrigin: 'left bottom',
            transition: 'all 0.2s',
            display: 'flex',
            alignItems: 'center',
            cursor: 'pointer',
            ...getLabelStyles(),
          }}
        >
          {label} {required && <span style={requiredDotStyles}>*</span>}
        </label>
      )}
    </components.ValueContainer>
  );
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM