执行React方法3次,并在第三次尝试时执行一个操作



我有一个呼叫端点以获取一些资源,后端人员建议尝试呼叫3次,每次呼叫之间延迟5秒。所以我创建了下面的函数…

const timeout = delay => {
return new Promise(resolve => setTimeout(resolve, delay))
}
const retry = useRef(0)
const fetchAPIResource = useCallback(
async () =>
await getStatus(transactionID)
.then(async res => {
if (res?.status === 204) {
await timeout(5000)
fetchAPIResource()
}
if (!res?.data?.receipt_is_settled && retry.current !== 3) {
await timeout(5000)
fetchAPIResource()
retry.current += 1
}
if (res?.data?.receipt_is_settled) {
setStatus('accepted')
setShow(false)
}
if (!res?.data?.receipt_is_settled && retry.current === 3) {
setStatus('declined')
setShow(false)
}
})
.catch(error => {
toast.error(error?.errors?.description || error?.description)
setStatus('declined')
}),
[],
)

我现在的问题是在最后一个调用执行的一瞬间,这个条件(!res?.data?.receipt_is_settled && retry.current === 3)为真,因此错误屏幕显示在成功屏幕之前,我需要帮助使这更好,所以我只得到错误屏幕或成功屏幕。

…此条件(!res?.data?)receipt_is_settled,,重试。Current === 3)为true,因此错误屏幕显示在成功屏幕之前…

这告诉我你使用retry.current作为你的渲染逻辑的一部分。因为它不在状态中(或纯粹从状态派生),所以不应该这样做。

我将使错误状态显式状态,并使重试计数器局部的useCallback回调。没有理由让该信息在处理重试逻辑的代码之外可用。

重试成功的(status = 200)请求似乎也很奇怪。

还要注意,将async/await.then/.catch混合会使代码难以遵循,并且

我试图重新编写代码,以提供一个示例,您可以如何做到这一点,但代码提出了很多问题:

  • res真的可以为空吗?
  • 当获得status而不是204时,res.data真的可以为空吗?
  • 当出现错误时,error真的可以为空吗?
  • 为什么有些事情算作重试,而其他事情不算作重试?
  • 为什么计数器没有复位?

所以这是我的看法,做出假设:

  1. 不需要重试已成功的操作。
  2. 所有执行超时和重试的分支都应算作重试。
  3. 除200或204之外的任何状态都是失败的,我们不应该重试
const fetchAPIResource = useCallback(async () => {
try {
for (let retries = 0; retries < 3; ++retries) {
const res = await getStatus();
if (res.status === 200 && res.data.receipt_is_settled) {
// All good
setStatus("accepted");
setShow(false);
return;
}
if (res.status !== 200 && res.status !== 204) {
throw new Error(`HTTP error ${res.status}`);
}
// Retry
await timeout(5000);
}
// Out of retries
setStatus("declined");
setShow(false);
} catch (error) {
// *** Can `error` really be nullish?
// *** Shouldn't there be a default if both of the below are `undefined`?
toast.error(error?.errors?.description || error?.description);
setStatus("declined");
// *** Shouldn't there be a `setShow(false);` here?
}
}, []);

上面没有显示:如果组件在这15秒内卸载,该进程可能应该被取消。

javascript按顺序运行代码,在你的代码中,你把

if (!res?.data?.receipt_is_settled && retry.current !== 3) {
await timeout(5000)
fetchAPIResource()
retry.current += 1
}

之前
if (!res?.data?.receipt_is_settled && retry.current === 3) {
setStatus('declined')
setShow(false)
}

所以条件retry.current === 3在第二次试验后总是为真。解决这个问题的方法是,您可以尝试输入以下代码:

if (!res?.data?.receipt_is_settled && retry.current === 3) {
setStatus('declined')
setShow(false)
}

if (!res?.data?.receipt_is_settled && retry.current !== 3) {
await timeout(5000)
fetchAPIResource()
retry.current += 1
}

最新更新