单击选项后,在 react-select/async 中触发 loadOptions
Trigger loadOptions in react-select/async once option has been click
我有一个异步 react-select
组件
import React, { useRef, useState } from "react";
import Async from "react-select/async";
const MySelect = ({
label,
options,
asyncSelect,
loadOptions,
components,
placeholder,
fixedHeight,
onSelect,
...props
}) => {
const ref = useRef();
const asyncRef = useRef();
const [fieldValue, setFieldValue] = useState();
// Gets called when an option is chosen or created.
const onChange = value => {
setFieldValue(value);
if (onSelect) onSelect(value);
};
// Toggle menu by presence of input.
// Reset value if input is emptied.
const onInputChange = (value, context) => {
if (!value && context.action === "input-change") {
onChange(null);
}
};
// Restore input value.
const onFocus = () => {
if (fieldValue) {
asyncRef.current.state.inputValue = fieldValue.label;
asyncRef.current.select.state.inputValue = fieldValue.label;
asyncRef.current.handleInputChange(fieldValue.label);
}
};
// Close menu when pressing enter. Submit does not work on mobile.
const onKeyDown = event => {
if (event.keyCode === 13) {
onMenuClose();
}
};
// Blur select element to trigger onFocus on next click.
const onMenuClose = () => {
asyncRef.current.select.blur();
};
return (
<>
<div ref={ref} />
<Async
ref={asyncRef}
{...props}
value={fieldValue}
components={components ? components : null}
loadOptions={loadOptions ? loadOptions : () => null}
placeholder={placeholder ? placeholder : "Select..."}
searchPromptText="Start Typing"
autoload
isSearchable
searchable
cacheOptions
// Hook into events to make the editing work.
onChange={onChange}
onInputChange={onInputChange}
onFocus={onFocus}
onKeyDown={onKeyDown}
onMenuClose={onMenuClose}
/>
</>
);
};
export default MySelect;
我在另一个组件中使用此组件从输入值加载数组和筛选选项
const loadOptions = async inputValue => {
return new Promise(resolve => resolve(getOptions(inputValue)));
};
const getOptions = async inputValue => {
// how to trigger this to be called within loadOptions when option is selected?
if (asyncOptions && asyncOptions.length > 0) {
const options = asyncOptions.filter(item =>
item.label.toLowerCase().startsWith(inputValue.trim().toLowerCase())
);
if (options && options.length > 0) {
return options;
}
return [];
}
await delayWithPromise(1000);
return [];
};
return (
<div className="App">
<MySelect
name="addressLookup"
className="addressLookupContainer"
label="Address Lookup"
asyncSelect
components={{
DropdownIndicator: () => null,
IndicatorSeparator: () => null,
NoOptionsMessage: val => <NoOptionsMsg>No Options</NoOptionsMsg>
}}
loadOptions={loadOptions}
onSelect={val => console.log(`${val.value} selected`)}
/>
</div>
);
但是,我想要它,所以当我 select 一个选项时,它会加载另一个列表(没有关闭列表,而是在旧列表位置加载一个新列表),但我不确定我是如何当我点击一个选项时,可以在 react-select/async
内重新触发 loadOptions
道具吗?
一个例子是地址搜索,您在其中搜索街道/post/zip 代码并且有一个选项说明该街道有多少个地址,然后 selecting 该选项然后触发器 loadOptions
进行 API 调用以查找该街道中的所有地址,因此,引入新的选项列表。希望这是有道理的?
如有任何帮助,我们将不胜感激。
我有一个 CodeSandbox 和一个例子。
我尝试了您发布的 Codesandbox link。
onSelect
道具可用于检测用户是否有 selected 任何内容。
const [firstValue, setFirstValue] = useState("");
const [secondValue, setSecondValue] = useState("");
const onSelect = option => {
if (firstValue) setSecondValue(option?.value);
else setFirstValue(option?.value);
};
现在我们知道,如果 firstValue
是 selected,我们需要切换选项。所以,按照这个逻辑 -
const getOptions = async inputValue => {
const optionChunk = firstValue ? secondOptions : firstOptions;
if (optionChunk && optionChunk.length > 0) {
const options = optionChunk.filter(item =>
item.label.toLowerCase().startsWith(inputValue.trim().toLowerCase())
);
if (options && options.length > 0) {
return options;
}
return [];
}
await delayWithPromise(1000);
return [];
};
查看代码框 link 了解更多详情。我在这里和那里调整了一些变量名,这对我来说更有意义。
编辑
当用户select第一个值时重新打开菜单 -
所以,当我们有 firstValue
而不是 secondValue
时,我们可以传递一个 prop
(比方说 - retainFocus
)-
<MySelect
... otherProps
retainFocus={!!firstValue && !secondValue}
/>
在 MySelect
中,我们可以在 retainFocus
上添加一个 useEffect
,如果作为 true
传递,它只会重新聚焦 select 框。
useEffect(() => {
if (retainFocus) {
asyncRef.current.select.focus();
}
}, [retainFocus]);
检查更新的代码和框 link。
编辑
我还添加了一个在用户输入为空时返回到第一个列表的方法。
我有一个异步 react-select
组件
import React, { useRef, useState } from "react";
import Async from "react-select/async";
const MySelect = ({
label,
options,
asyncSelect,
loadOptions,
components,
placeholder,
fixedHeight,
onSelect,
...props
}) => {
const ref = useRef();
const asyncRef = useRef();
const [fieldValue, setFieldValue] = useState();
// Gets called when an option is chosen or created.
const onChange = value => {
setFieldValue(value);
if (onSelect) onSelect(value);
};
// Toggle menu by presence of input.
// Reset value if input is emptied.
const onInputChange = (value, context) => {
if (!value && context.action === "input-change") {
onChange(null);
}
};
// Restore input value.
const onFocus = () => {
if (fieldValue) {
asyncRef.current.state.inputValue = fieldValue.label;
asyncRef.current.select.state.inputValue = fieldValue.label;
asyncRef.current.handleInputChange(fieldValue.label);
}
};
// Close menu when pressing enter. Submit does not work on mobile.
const onKeyDown = event => {
if (event.keyCode === 13) {
onMenuClose();
}
};
// Blur select element to trigger onFocus on next click.
const onMenuClose = () => {
asyncRef.current.select.blur();
};
return (
<>
<div ref={ref} />
<Async
ref={asyncRef}
{...props}
value={fieldValue}
components={components ? components : null}
loadOptions={loadOptions ? loadOptions : () => null}
placeholder={placeholder ? placeholder : "Select..."}
searchPromptText="Start Typing"
autoload
isSearchable
searchable
cacheOptions
// Hook into events to make the editing work.
onChange={onChange}
onInputChange={onInputChange}
onFocus={onFocus}
onKeyDown={onKeyDown}
onMenuClose={onMenuClose}
/>
</>
);
};
export default MySelect;
我在另一个组件中使用此组件从输入值加载数组和筛选选项
const loadOptions = async inputValue => {
return new Promise(resolve => resolve(getOptions(inputValue)));
};
const getOptions = async inputValue => {
// how to trigger this to be called within loadOptions when option is selected?
if (asyncOptions && asyncOptions.length > 0) {
const options = asyncOptions.filter(item =>
item.label.toLowerCase().startsWith(inputValue.trim().toLowerCase())
);
if (options && options.length > 0) {
return options;
}
return [];
}
await delayWithPromise(1000);
return [];
};
return (
<div className="App">
<MySelect
name="addressLookup"
className="addressLookupContainer"
label="Address Lookup"
asyncSelect
components={{
DropdownIndicator: () => null,
IndicatorSeparator: () => null,
NoOptionsMessage: val => <NoOptionsMsg>No Options</NoOptionsMsg>
}}
loadOptions={loadOptions}
onSelect={val => console.log(`${val.value} selected`)}
/>
</div>
);
但是,我想要它,所以当我 select 一个选项时,它会加载另一个列表(没有关闭列表,而是在旧列表位置加载一个新列表),但我不确定我是如何当我点击一个选项时,可以在 react-select/async
内重新触发 loadOptions
道具吗?
一个例子是地址搜索,您在其中搜索街道/post/zip 代码并且有一个选项说明该街道有多少个地址,然后 selecting 该选项然后触发器 loadOptions
进行 API 调用以查找该街道中的所有地址,因此,引入新的选项列表。希望这是有道理的?
如有任何帮助,我们将不胜感激。
我有一个 CodeSandbox 和一个例子。
我尝试了您发布的 Codesandbox link。
onSelect
道具可用于检测用户是否有 selected 任何内容。
const [firstValue, setFirstValue] = useState("");
const [secondValue, setSecondValue] = useState("");
const onSelect = option => {
if (firstValue) setSecondValue(option?.value);
else setFirstValue(option?.value);
};
现在我们知道,如果 firstValue
是 selected,我们需要切换选项。所以,按照这个逻辑 -
const getOptions = async inputValue => {
const optionChunk = firstValue ? secondOptions : firstOptions;
if (optionChunk && optionChunk.length > 0) {
const options = optionChunk.filter(item =>
item.label.toLowerCase().startsWith(inputValue.trim().toLowerCase())
);
if (options && options.length > 0) {
return options;
}
return [];
}
await delayWithPromise(1000);
return [];
};
查看代码框 link 了解更多详情。我在这里和那里调整了一些变量名,这对我来说更有意义。
编辑
当用户select第一个值时重新打开菜单 -
所以,当我们有 firstValue
而不是 secondValue
时,我们可以传递一个 prop
(比方说 - retainFocus
)-
<MySelect
... otherProps
retainFocus={!!firstValue && !secondValue}
/>
在 MySelect
中,我们可以在 retainFocus
上添加一个 useEffect
,如果作为 true
传递,它只会重新聚焦 select 框。
useEffect(() => {
if (retainFocus) {
asyncRef.current.select.focus();
}
}, [retainFocus]);
检查更新的代码和框 link。
编辑
我还添加了一个在用户输入为空时返回到第一个列表的方法。