首页 > 解决方案 > 如何修复两个绑定需要同时更新的属性的 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])

我怎样才能使它如此匹配并且查询状态在没有无限循环的情况下同时更新?

标签: reactjsuse-effect

解决方案


您可以将依赖代码放在 useEffect 中并调用它。这样,函数就不会在每次渲染时都重新声明。它仅在重新运行效果时更改。

这可能在某处缺少等待或异步修饰符,但要给出这个想法。

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])

推荐阅读