我有一个自动完成组件:
自动完成
function Autocomplete() {
const [ matches, setMatches ] = useState([ 'game' ]);
const [ query, setQuery ] = useState('');
const [ menuState, setMenuState ] = useState(false);
useEffect(() => {
if(query !== ""){
updateQuery()
}
}, [query])
const updateQuery = async () => {
const data = await props.searchQuery(query);
if(data.length > 1 ){
setMenuState(true);
setMatches(data);
} else if (data.length < 1){
setMenuState(false);
setMatches([]);
}
}
return (
<div className={rootClassName(null, [props.className], classStates)} style={styles}>
<div className='Autocomplete__Trigger'>
<input
className='Input'
type='text'
placeholder={props.placeholder}
value={query}
onChange={ e => setQuery(e.target.value) }
onKeyDown={ handleKeyPress }
/>
</div>
<div className='Autocomplete__Menu' role='menu'>
{
//Custom if function
If(matches.length > 0, () => (
<div className='Autocomplete__Content'>
{
//Custom loop
For(matches, (item, index) => (
//loops through matches
))
}
</div>
)).EndIf()
}
</div>
</div>
);
}
export default Autocomplete;
基本原理如下:
- 当输入内容时,设置查询字符串:
<input
onChange={ e => setQuery(e.target.value) }
/>
- 立即设置查询状态,
useEffect
和updateQuery()
被调用:
useEffect(() => {
//If input is empty
if(query !== ""){
updateQuery()
}
}, [query])
- 在
updateQuery()
中,自动完成中的所有菜单项都是从API请求的,并且匹配被设置为循环并决定菜单是否打开:
const updateQuery = async () => {
const data = await props.searchQuery(query);
if(data.length > 1 ){
setMenuState(true);
setMatches(data);
} else if (data.length < 1){
setMenuState(false);
setMatches([]);
}
}
我遇到的问题是匹配状态滞后,但如果我将其添加到useEffect
,我会得到一个无限循环,因为updateQuery
总是被调用:
useEffect(() => {
//If input is empty
if(query !== ""){
updateQuery()
}
}, [query, matches])
如何使匹配和查询状态在没有无限循环的情况下同时更新?
你可以把依赖的代码和它的调用放在useEffect里面。这样,函数就不会在每次渲染时都重新声明。只有当效果重新运行时才会改变。
这里可能缺少await或async修饰符,但是为了给你一个想法。
useEffect(() => {
const updateQuery = async () => {
const data = await props.searchQuery(query);
if(data.length > 1 ){
setMenuState(true);
setMatches(data);
} else if (data.length < 1){
setMenuState(false);
setMatches([]);
}
}
//If input is empty
if(query !== ""){
updateQuery()
}
}, [query])