React DOM 在数组 属性 状态改变后不重新渲染

React DOM not re-rendering after state change of array property

我知道这个问题很常见,大多数人可能会认为这是重复的,但我无能为力,这就是我来这里的原因。

我有一个名为 App 的 React 组件,它是一个功能组件。

App 组件开始

function App() {
  
  const [results, setResults] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [name, setName] = useState('');
  const [isNameSelected, setIsNameSelected] = useState(false);
  ...

有一个子组件目前运行不正常,它是 App 函数的 return 组件的一部分。

App 组件的 return 语句中的代码部分:

<ListGroup className="typeahead-list-group">
  {!isNameSelected &&
     results.length > 0 &&
     results.map((result: Result) => (
       <ListGroupItem
         key={result.cik}
         className="typeahead-list-group-item"
         onClick={() => onNameSelected(result)}
       >
         {result.cik + ' | ' + result.name}
       </ListGroupItem>
     ))}
</ListGroup>

results 的更改由组件 FormControlonChange 函数处理,这里也是 Appreturn 语句的一部分:

<FormControl
  placeholder="Entity/CIK"
  id="searchInput"
  type="text"
  autoComplete="off"
  onChange={handleInputChange}
  value={name}
/>

handleInputChangeApp 函数中定义为:

const handleInputChange = (e: any) => { // Triggers when search bar is changed
  // remove error bubble
  setAlertMessage(new AlertData('', false));
  const nameValue = e.target.value; // get the new input
  setName(nameValue); // set the new input
  // even if we've selected already an item from the list, we should reset it since it's been changed
  setIsNameSelected(false);
  setResults([]); // clean previous results
  if (nameValue.length > 1) { // if the input is more than 1 character
    setIsLoading(true); // set loading to true
    updateSearchInput(nameValue)  // get the results
      .then((res) => {
        setResults(res as React.SetStateAction<never[]>); // set the results
        setIsLoading(false); // set loading to false
      })
      .catch((error) => {
        // error bubble
        let strError = error.message;
        strError = strError.split(':').pop();
        let errorMessage: AlertData = new AlertData(strError, true); // create error message for empty search
        setAlertMessage(errorMessage); // set alert message
        // loading spinner
        setIsLoading(false);
      });
  }
}

然而,当表单控件中的输入发生变化时,例如输入整个单词,搜索功能会起作用,用建议的单词填充 DOM。但是,当我非常快地清除 FormControl 中的值时(通过快速连续按几次 Backspace/Delete),搜索结果就会保留下来。缓慢执行或一次选择并清除它不会显示这种不稳定的行为。

我已经使用 console.log 在空组件中打印出 results 的值,如下所示:

{console.log(results) && (<div><div/>)}

在App的return语句中查看results的内容是什么。但是它确实表明 results 值没有被 setResults().

更新

但是这里使用的其他状态不存在这个问题。为什么?

编辑

来自下面从 @ghybs 接受的答案。这是通话可能发生的事情的时间表:

  1. 输入搜索
  2. await 调用运行但请求响应很慢,因此需要一段时间。
  3. 删除搜索中的所有关键字
  4. resultshandleInputChange 调用中用 setResults([]) 清空。
  5. 等待调用结束。 setResults(res as React.SetStateAction<never[]>) 运行使 results 非空。

您很可能只有大量并发请求(每次击键 1 个,包括返回 space?),以及来自 updateSearchInput 异步函数的无序结果:最后收到的请求会覆盖您的 results,但那个可能不是你最后一次击键(从你的文本区域中删除最后一个字符的那个)。

通常情况下,如果空搜索比大量单词搜索更快,空输入的结果确实会清除您的 results,但随后这些会被先前搜索的结果再次填充。