简体   繁体   English

拨打 onClick function 等待上一个电话结束

[英]Make an onClick function wait the previous call to end

I'm working with React, And I have a problem synchronizing clicks successively (onClick events):我正在使用 React,我在连续同步点击时遇到问题(onClick 事件):

My button triggers a function that calls two functions resetViews and chargeViews ( chargeViews takes time), so when I click two times rapidely:我的按钮触发了一个 function 调用两个函数resetViewschargeViewschargeViews需要时间),所以当我快速点击两次时:

  • resetView is executed fine (it sets viewsRef.current to null) resetView执行得很好(它将viewsRef.current设置为 null)
  • then chargeViews is called but as it is taking time it won't update viewsRef.current right after.然后chargeViews但由于它需要时间,因此不会立即更新viewsRef.current
  • so resetView is called but viewsRef.current is still null (because chargeViews doesn't update it yet) so it will do nothing,所以调用了resetViewviewsRef.current仍然是 null(因为chargeViews还没有更新它)所以它什么都不做,
  • then I get two delayed executions of chargeViews然后我得到两次延迟执行的chargeViews
  • so after two clicks I got 1 execution of resetView and two delayed executions of chargeViews所以点击两次后,我执行了 1 次resetView和两次延迟执行chargeViews

What I want is after clicking, block everything (even if the user clicks we do nothing) and execute resetView then chargeViews and then unblock to receive another click and do the same work.我想要的是在点击后阻止所有内容(即使用户点击我们什么都不做)并执行resetView然后chargeViews然后取消阻止以接收另一次点击并做同样的工作。

<MyButton onClick={() => {
  resetViews();
  chargeViews();
 }}> 
  Click me 
 </MyButton>

The function that takes time需要时间的function

const chargeViews = () => {
  if(!viewsRef.current){
   ...
   reader.setUrl(url).then(()=>{
   reader.loadData().then(()=>{
   ...
   viewsRef.current = reader.getData();
})})
}}

The function that getting ignored if I click so fast, (It works fine if I click and I wait a little bit then I click again) but if I click and click again fast It is ignored. function 如果我点击得太快就会被忽略,(如果我点击它工作正常然后我等一下然后我再次点击)但是如果我点击并再次快速点击它被忽略。

const resetViews = () => {
  if (viewsRef.current){
   ...
   viewsRef.current = null;
}}

I'm not totally sure to grasp the whole issue... this would be a comment if it didn't require such a long text.我不确定是否掌握了整个问题……如果不需要这么长的文本,这将是一条评论。

Anyway as far as you need to disable the button once it's clicked you should deal with it at the beginning of its onclick handler:无论如何,就您需要在单击按钮后禁用该按钮而言,您应该在其 onclick 处理程序的开头处理它:

$(this.event.target).prop('disabled', true);

and reset it at the end:并在最后重置它:

$(this.event.target).prop('disabled', false);

In general what you did was correct in terms of calling a number of functions to be executed in chain inside the handler.一般来说,就调用要在处理程序内链中执行的许多函数而言,您所做的是正确的。 But those 2 functions seem to have a promise invocation.. in that case those won't be executed in chain waiting for the first one to finish.但是这两个函数似乎有一个 promise 调用。在那种情况下,它们不会在链中执行,等待第一个函数完成。

So you should pass the second invocation as a callback to the first, to have the chance to call it ONLY once the first one finished its job.因此,您应该将第二次调用作为回调传递给第一次调用,以便只有在第一次调用完成后才有机会调用它。

I hope someone will just go straight to the point suggesting how making an async function "await" so that whatever it does, when invocated it will be waited for to complete before the next statement is evaluated.我希望有人会 go 直截了当地建议如何使异步 function “等待”,以便无论它做什么,在调用它时都会等待它完成,然后再评估下一个语句。 Usually it's just a matter of adding await before its signature but there are some caveats.通常这只是在其签名之前添加await的问题,但有一些注意事项。

First, you need to convert your Promise-utilizing functions into async functions and then await them when invoking them.首先,您需要将使用 Promise 的函数转换为异步函数,然后在调用它们时等待它们。 This will make it easier to control the order of execution:这将使控制执行顺序变得更容易:

const chargeViews = async () => {
  if(!viewsRef.current){
   ...
   await reader.setUrl(url);
   await reader.loadData();
   ...
   viewsRef.current = reader.getData();
  }
}

Then, you need an isExecuting ref that will be true when other invokations are executing and false when none are currently executing:然后,您需要一个 isExecuting ref,它在其他调用正在执行时为真,在当前没有执行时为假:

const isExecuting = useRef(false);

const handleClick = async () => {
  if (!isExecuting.current) {
    // block other clicks from performing actions in parallel
    isExecuting.current = true;
    try {
      resetViews();
      await chargeViews();
    } finally {
      // unblock other clicks
      isExecuting.current = false;
    }
  }
};

Lastly, use the newly-created handleClick function in your JSX:最后,在您的 JSX 中使用新创建的handleClick function:

<MyButton onClick={handleClick}>
  Click me
</MyButton>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM