点击外部时,react-select 不会关闭

问题描述 投票:0回答:3

我正在使用react-select并对其进行了一些自定义。 我尝试修改 ValueContainer 和 SelectContainer 组件,这会导致一些问题。选择值后单击下拉列表外部时,下拉列表不会关闭。我想知道是否有人能看到我在这里做错了什么?

我假设下拉列表不会关闭,因为输入的 onBlur 事件不会触发。例如,当我单击

closeMenuOnSelect
= true 的值后,输入不会重新获得焦点。我还假设这是因为反应选择由于某种原因无法找到输入,因为我修改了结构。可能缺少一些参考资料或其他东西,但我不明白在哪里可以获得它们以及将它们放在哪里。有谁知道吗?

这是我的自定义选择组件:

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} />;
};

这是我的定制

<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>
);
javascript reactjs react-select
3个回答
2
投票

问题在于我如何发送自定义组件。你不应该在那里传递道具。我认为这可能会破坏一些重要的 ReactSelect 属性,例如 refs 等。

像这样发送组件。也在该对象中定义您的自定义属性:

  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} />;

然后您可以使用

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>
  );
};

0
投票

问题出在 ValueContainer 中,由于我们的选择器失去了焦点,解决这个问题最简单的方法就是将焦点添加到 ValueContainer

const refSelect = useRef<any>(null);
    
const ValueContainer: React.FC<CustomValueContainerProps> = ({
  ...props
}) => {
  let [values, input] = props.children;

    if (refSelect?.current) {
      refSelect.current.focus();
    }

  return (
    <components.ValueContainer {...props}>
      {input}
      {values}
    </components.ValueContainer>
  );
};
    
<CustomSelect
    value={value}
    classNamePrefix={'Select'}
    options={options}
    onChange={handleChange}
    closeMenuOnSelect={closeMenuOnSelect}
    ref={refSelect}
    components={{
      ValueContainer,
    }}
/>

0
投票

根据 Dmytry 的回答,我唯一要改变的就是改变选择实际上应该具有焦点的时间。否则,焦点将始终被您使用的任何页面上的组件劫持。

const refSelect = useRef<any>(null);
    
const ValueContainer: React.FC<CustomValueContainerProps> = ({
  ...props
}) => {
  let [values, input] = props.children;

//only gain focus if the menu is open. This also helps with cross click close when closeMenuOnSelect is false
    if (refSelect?.current && props.selectProps.menuIsOpen) {
            refSelect.current.focus();
        }

  return (
    <components.ValueContainer {...props}>
      {input}
      {values}
    </components.ValueContainer>
  );
};
    
<CustomSelect
    value={value}
    classNamePrefix={'Select'}
    options={options}
    onChange={handleChange}
    closeMenuOnSelect={closeMenuOnSelect}
    ref={refSelect}
    components={{
      ValueContainer,
    }}
/>

© www.soinside.com 2019 - 2024. All rights reserved.