背景
很多时候都会遇到这么一种场景:需要不断发送请求,并且新请求发出去的时候,旧请求就过期了。但如果旧请求反而后收到结果,就可能会覆盖更新的结果,造成数据错误。
举例来说,假设要实现一个实时搜索框,用户在键入的过程中就可以看到结果,不需要按回车键。例如用户输入 “cat”,则会依次发送 3 个请求:“c”、“ca”、“cat”。
这时候,即便 “ca” 的结果比 “cat” 后到,也一定不能覆盖 “cat” 的结果。
实现
代码
示例代码如下:
const [searchQuery, setSearchQuery] = useState('');
useLayoutEffect(() => {
// 初始时,默认请求有效
let isActive = true;
if (searchQuery) {
// 发送请求
getResult(searchQuery)
// 收到结果,这时候请求可能已经无效了
.then((result) => {
// 只有请求有效时,才展示数据
if (isActive) {
display(result);
}
})
}
return () => {
// 如果 searchQuery 更新,则请求无效
isActive = false;
};
}, [searchQuery]);
说明
需要说明的几点:
- 上面用的
useLayoutEffect
是useEffect
的同步版本,道理一样; searchQuery
变化时,旧的useLayoutEffect
会执行销毁逻辑,即isActive = false;
,请求失效。销毁之后,即便收到结果,也不会展示;反之,如果searchQuery
没有变化,收到结果之后就会正常展示;- 如果有办法取消请求自然更好,在
return () => {}
函数中取消请求即可;