react-select 在外面点击时不会关闭
react-select wont close when clicking outside
我正在使用 react-select 并对其进行了一些自定义。
我试图修改导致一些问题的 ValueContainer 和 SelectContainer 组件。在 select 编辑了一个值后,当我在下拉列表外部单击时,下拉列表不会关闭。我想知道是否有人可以看到我在这里做错了什么?
我假设下拉菜单不会关闭,因为输入的 onBlur 事件不会触发。例如,在我单击 closeMenuOnSelect
= true 的值后,输入没有重新获得焦点。我还假设这是因为 react-select 由于某种原因无法找到输入,因为我已经修改了结构。可能缺少一些参考或其他东西,但我不明白从哪里得到它们以及把它们放在哪里。有人知道吗?
这是我的自定义 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} />;
};
这是我的习惯 <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>
);
问题在于我如何发送自定义组件。你不应该在那里传递道具。我认为这可能会破坏一些重要的 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>
);
};
我正在使用 react-select 并对其进行了一些自定义。 我试图修改导致一些问题的 ValueContainer 和 SelectContainer 组件。在 select 编辑了一个值后,当我在下拉列表外部单击时,下拉列表不会关闭。我想知道是否有人可以看到我在这里做错了什么?
我假设下拉菜单不会关闭,因为输入的 onBlur 事件不会触发。例如,在我单击 closeMenuOnSelect
= true 的值后,输入没有重新获得焦点。我还假设这是因为 react-select 由于某种原因无法找到输入,因为我已经修改了结构。可能缺少一些参考或其他东西,但我不明白从哪里得到它们以及把它们放在哪里。有人知道吗?
这是我的自定义 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} />;
};
这是我的习惯 <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>
);
问题在于我如何发送自定义组件。你不应该在那里传递道具。我认为这可能会破坏一些重要的 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>
);
};