我如何修复一个useEffect无限循环与两个属性绑定,需要在同一时间更新?



我有一个自动完成组件:

自动完成

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;

基本原理如下:

  1. 当输入内容时,设置查询字符串:
<input
onChange={ e => setQuery(e.target.value) }
/>
  1. 立即设置查询状态,useEffectupdateQuery()被调用:
useEffect(() => { 
//If input is empty
if(query !== ""){
updateQuery()
}
}, [query])
  1. 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])

最新更新