你可能在React useEffect请求中遇到同样的问题
需要实现的功能
根据切换不同的Tabs,获取相应的数据并显示在页面上。
出现的问题
当多次快速切换选项时,异步请求时间问题,导致返回顺序不一定按照发送请求的顺序返回。
要触发这个bug,需要按照这个顺序执行:
- 选择
红灯
触发fetchLight('红灯')
- 选择
黄灯
触发fetchLight('黄灯')
这个过程是红灯
还在loading的时候马上切换回黄灯
黄灯
请求结束后,触发了黄灯
的 Effect,调用了setBio('黄灯状态...')
。红灯
请求结束后,触发了红灯
的 Effect,调用了setBio('红灯状态...')
。
最终选中的Button是黄灯
,而结果却是红灯状态...
解决问题
原本问题代码
useEffect(() => {
setBio(null);
fetchLight(light).then(result => {
setBio(result);
});
}, [light]);
试着把下面的代码替换掉码上掘金里运行着的useEffect。 修复后的代码
useEffect(() => {
let ignore = false;
setBio(null);
fetchLight(light).then(result => {
if (!ignore) {
setBio(result);
}
});
return () => {
ignore = true;
}
}, [light]);
解释原因
因为两个异步操作相互竞争,它们可能以意想不到的顺序到达,这样的错误被称为竞争条件(race conditions)
。
在每次Effect再次运行之前,调用React的清理函数。
设置了ignore后,每个渲染周期的 Effect 都有自己的 ignore 变量。
初始状态下,ignore 变量都为 false。之后,如果你选择不同交通灯时,那么在Effect再次运行之前,在return中执行清理函数,会把上一个交通灯的状态改为true。
所以每个接口请求的时长不同变得无所谓了。只有最后一个灯触发的Effect 的 ignore 变量为 false,它才会调用 setBio(result)。过去的 Effect 已经被清理。