React中使用的Autosuggest这个第三方插件
问题描述:首次在input输入任意内容后,随后全部删除,当清空后会报如下错误。然后再次输入,再次清空,则不会报错。
从描述来看,是因为非受控组件变成受控才导致的问题。请问有什么解决办法吗?
下面是示例代码,没贴样式
const AsyncAutoComplete = ({ inputField, hooks, onChange, section, ...props }) => {
const { loadAsyncDropdown} = useForm(hooks);
const [optionValue, setValue] = useState('');
const [options, setOptions] = useState([]);
const [cache, setcache] = useState({});
const [timer, setTimer] = useState(0);
// 设置缓存
const setCache = (key, options) => {
// 无法找到匹配则设置一个空项
if (options.length === 0) options = [{ label: 'No Options', value: '' }];
cache[key] = options;
// 同时缓存返回数据中的数据项
options.forEach((i) => {
cache[i.value] = [i];
});
return options;
};
// 获取关键字数据,有缓存从缓存获取否则从远程服务器加载
const getData = async (value, bySearch = false) => {
let options;
if (value === '') {
cache.empty = [{ label: 'No Options', value: '' }];
options = cache.empty;
} else if (cache[value]) {
options = cache[value];
} else {
options = await loadAsyncDropdown(inputField, value);
options = options.options;
options = setCache(value, options);
}
setOptions(options);
if (options.length === 1 && options[0].value) onChange(options[0]);
else if (bySearch) {
document.querySelector('#myinput').focus();
}
return options;
};
const search = async () => {
clearTimeout(timer); // 清空计时器,防止没法查询
if (optionValue.length > 2) {
getData(optionValue, true);
}
};
// 点击下拉弹出层时返回需要的内容,labe和value一样随便一个
const getSuggestionValue = (suggestion) => suggestion.value;
// 渲染弹出层的每个项的格式
const renderSuggestion = (suggestion) => <div>{suggestion.label}</div>;
// 输入框输入内容时响应的事件
const onInput = async (newValue) => {
setValue(newValue);
if (newValue.length === 0) {
// 清空内容
onChange({ label: '', value: '' });
} else if (newValue.length === 13) getData(newValue);
};
const onBlur = (e) => {
let t = setTimeout(() => {
let item = cache[optionValue];
if (!item || item.length !== 1 || item[0].value !== optionValue) {
setValue(''); // 清空内容
onChange({}); // 更新其他组件值
}
}, 200);
setTimer(t);
};
const onClick = () => {
let el = document.querySelector('#myinput');
el.selectionStart = 0;
el.selectionEnd = 0;
};
const onKeyDown = (e) => {
let el = document.querySelector('#myinput');
if (el.selectionStart === 0 && optionValue.length > 0) {
setValue('');
}
};
const inputProps = {
placeholder: "输入关键字查找",
value: optionValue || '',
onChange: (e, obj) => {
onInput(obj.newValue);
},
id: 'myinput',
onBlur,
onClick,
onKeyDown,
};
const onSuggestionsClearRequested = () => {
setOptions([]);
};
const onSuggestionsFetchRequested = async ({ value }) => {
if (value.length === 13) {
getData(value);
}
};
return (
<>
<div>
<Autosuggest
suggestions={options}
onSuggestionsClearRequested={onSuggestionsClearRequested}
onSuggestionsFetchRequested={() => {}}
getSuggestionValue={getSuggestionValue}
renderSuggestion={renderSuggestion}
inputProps={inputProps}
/>
<SearchIcon onClick={search} />
</div>
)}
</>
};
export default AsyncAutoComplete;
AsyncAutoComplete.propTypes = {
inputField: PropTypes.shape({
name: PropTypes.string.isRequired,
placeholder: PropTypes.string.isRequired,
isRequired: PropTypes.bool.isRequired,
isEnabled: PropTypes.bool.isRequired,
isTouched: PropTypes.bool.isRequired,
isValid: PropTypes.bool.isRequired,
errorMsg: PropTypes.string.isRequired,
}).isRequired,
onChange: PropTypes.func.isRequired,
};