许多应用使用 Effect 来发起数据获取请求。像这样在 Effect 中写一个数据获取请求是相当常见的:
function SearchResults({ query }) {
useEffect(() => {
// 🔴 避免:没有清除逻辑的获取数据
fetchResults(query, page).then(json => {
setResults(json);
});
}, [query, page]);
}
然而,上面的代码有一个问题。假设快速地输入 “hello”。那么 query 会从 “h” 变成 “he”,“hel”,“hell” 最后是 “hello”。这会触发一连串不同的数据获取请求,但无法保证对应的返回顺序。例如,“hell” 的响应可能在 “hello” 的响应之后返回。由于它的 setResults() 是在最后被调用的,你将会显示错误的搜索结果。
这种情况被称为 “竞态条件”:两个不同的请求 “相互竞争”,并以与你预期不符的顺序返回。
为了修复这个问题,需要添加一个清理函数来忽略较早的返回结果:
useEffect(() => {
let ignore = false;
fetchResults(query, page).then(json => {
if (!ignore) {
setResults(json);
}
});
return () => {
ignore = true;
};
}, [query, page]);
这确保了在 Effect 中获取数据时,除了最后一次请求的所有返回结果都将被忽略。