反应-旧的承诺会覆盖新的结果

时间:2019-02-26 12:41:55

标签: reactjs promise es6-promise

我有一个问题,我可以肯定我不是唯一一个遇到问题的人。尽管我试图找到解决方案,但我并没有真正找到适合我目的的东西。

我不会发布太多代码,因为它不是真正的代码问题,而是更多的逻辑问题。

想象一下,我有以下钩子:

useEffect(() => {
    fetchFromApi(props.match.params.id);
}, [props.match.params.id]);

想象一下fetchFromApi的结果显示在UI的一个简单表中。

现在,可以说用户单击导航中的一个实体,因此浏览器URL中的ID属性更改,并且效果触发,从而导致API调用。假设具有此特定ID的呼叫需要5秒钟。

在这5秒钟内,用户再次单击导航中的元素,因此该挂钩再次触发。这次,API调用仅需0.1秒。结果立即显示。

但是第一个电话仍在运行。完成后,它将覆盖当前结果,从而导致在错误的导航部分中显示错误的数据。

有没有简单的方法可以解决此问题?我知道我默认情况下无法取消承诺,但是我也知道有一些方法可以实现它...

此外,fetchFromApi可能不是单个API调用,而是对多个端点的多次调用,因此整个过程可能会变得非常棘手...

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

此问题的解决方案非常简单,您只需确定所获得的响应是​​否来自最新的API调用,然后才能确定。您可以通过将triggerTime存储在ref中来实现。如果再次调用了API调用,则ref将存储一个不同的值,但是闭包变量将保留相同的先前设置的值,这意味着在此之后又触发了另一个API调用,因此我们不需要接受当前结果。

const timer = useRef(null);
useEffect(() => {
    fetchFromApi(props.match.params.id, timer);
}, [props.match.params.id]);

function fetchFromApi(id, timer) {
     timer.current = Date.now();
     const triggerTime = timer.current;
     fetch('path').then(() => {
         if(timer.current == triggerTime) {
              // process result here
              // accept response and update state
         }
     })

} 

处理此类情况的其他方法可以取消先前待处理的API请求。如果您使用Axios,它将为您提供可以使用的cancelToken,同样,您也可以取消XMLHttpRequests。