ReactJS - 重置正在进行的超时并通过按同一按钮重新激活

问题描述 投票:0回答:1

我有一个带有回调函数的按钮。 我希望按钮在单击时启动 5 秒延迟的超时。 如果在 5 秒内再次单击该按钮,我希望重置超时而不调用超时处理程序。 然后当 5 秒过去时,处理程序被调用。

[timeoutHasInitiated, setTimeoutHasInitiated] = useState(false);

function callbackFunction() {
    if (!timeoutHasInitiated) {
        setTimeoutHasInitiated(true);
        console.log('Button clicked: Timeout Started.');

        const timeout = setTimeout(() => {
            setTimeoutHasInitiated(false);
            console.log('Timeout has Finished.');
          }, 5000);
        return () => clearTimeout(timeout);
    }
    else {
        console.log('Button clicked while timeout in progress');
    }
}

在上面的代码中,超时后单击按钮不会执行任何操作。

如果我尝试类似的事情:

function callbackFunction() {
    clearTimeout(timeout);
    const timeout = setTimeout(() => {
        setTimeoutHasInitiated(false);
        console.log('Timeout has Finished.');
      }, 5000);
    return () => clearTimeout(timeout);
}

我收到错误:

在声明之前使用块范围变量“timeout”。

变量“超时”在分配之前使用。

如果我尝试先声明超时,然后再将其分配给 setTimeout() ,如下所示:

function callbackFunction() {
    let timeout;
    clearTimeout(timeout);
    timeout = setTimeout(() => {
        setTimeoutHasInitiated(false);
        console.log('Timeout has Finished.');
      }, 5000);
    return () => clearTimeout(timeout);
}

在 setTimeout() 之前调用的clearTimeout(timeout)似乎没有做任何事情,因为多次按下按钮会启动多个超时。

我想我可以在单击按钮后禁用该按钮作为解决方法,但我想知道是否有一种方法可以对我描述的所需行为进行编程。

javascript reactjs typescript react-hooks timeout
1个回答
0
投票

如果您将

timeout
的声明移至
callbackFunction
之外,它应该按您的预期工作。

let timeout;
function callbackFunction() {
    clearTimeout(timeout);
    timeout = setTimeout(() => {
        setTimeoutHasInitiated(false);
        console.log('Timeout has Finished.');
    }, 5000);
    return () => clearTimeout(timeout);
}

callbackFunction
的每次调用都会创建一个新的执行上下文,因此当前每个调用都在访问其自己的本地作用域的
timeout
声明,这就是为什么您会看到多次按下按钮引发多个超时。 或者您可以使用
timeout
this.timeout
范围限定为函数,但由于是自学,我不确定这种方法的缺点。

function callbackFunction() {
    clearTimeout(this.timeout);
    this.timeout = setTimeout(() => {
        setTimeoutHasInitiated(false);
        console.log('Timeout has Finished.');
    }, 5000); 
    return () => clearTimeout(timeout); 
}
© www.soinside.com 2019 - 2024. All rights reserved.