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
的更改由组件 FormControl
的 onChange
函数处理,这里也是 App
的 return
语句的一部分:
<FormControl
placeholder="Entity/CIK"
id="searchInput"
type="text"
autoComplete="off"
onChange={handleInputChange}
value={name}
/>
handleInputChange
在 App
函数中定义为:
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 接受的答案。这是通话可能发生的事情的时间表:
- 输入搜索
await
调用运行但请求响应很慢,因此需要一段时间。
- 删除搜索中的所有关键字
results
在 handleInputChange
调用中用 setResults([])
清空。
- 等待调用结束。
setResults(res as React.SetStateAction<never[]>)
运行使 results
非空。
您很可能只有大量并发请求(每次击键 1 个,包括返回 space?),以及来自 updateSearchInput
异步函数的无序结果:最后收到的请求会覆盖您的 results
,但那个可能不是你最后一次击键(从你的文本区域中删除最后一个字符的那个)。
通常情况下,如果空搜索比大量单词搜索更快,空输入的结果确实会清除您的 results
,但随后这些会被先前搜索的结果再次填充。
我知道这个问题很常见,大多数人可能会认为这是重复的,但我无能为力,这就是我来这里的原因。
我有一个名为 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
的更改由组件 FormControl
的 onChange
函数处理,这里也是 App
的 return
语句的一部分:
<FormControl
placeholder="Entity/CIK"
id="searchInput"
type="text"
autoComplete="off"
onChange={handleInputChange}
value={name}
/>
handleInputChange
在 App
函数中定义为:
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 接受的答案。这是通话可能发生的事情的时间表:
- 输入搜索
await
调用运行但请求响应很慢,因此需要一段时间。- 删除搜索中的所有关键字
results
在handleInputChange
调用中用setResults([])
清空。- 等待调用结束。
setResults(res as React.SetStateAction<never[]>)
运行使results
非空。
您很可能只有大量并发请求(每次击键 1 个,包括返回 space?),以及来自 updateSearchInput
异步函数的无序结果:最后收到的请求会覆盖您的 results
,但那个可能不是你最后一次击键(从你的文本区域中删除最后一个字符的那个)。
通常情况下,如果空搜索比大量单词搜索更快,空输入的结果确实会清除您的 results
,但随后这些会被先前搜索的结果再次填充。