Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在onClick事件中使用setTimeout来限制按钮的快速点击是否是一种不好的做法?_Javascript_Reactjs - Fatal编程技术网

Javascript 在onClick事件中使用setTimeout来限制按钮的快速点击是否是一种不好的做法?

Javascript 在onClick事件中使用setTimeout来限制按钮的快速点击是否是一种不好的做法?,javascript,reactjs,Javascript,Reactjs,我有一个按钮,当本地useState钩子为true时被禁用,当为false时被启用。我的onClick事件调用一个handleclick函数,它做的第一件事是将这个钩子设置为true(如果它还不是true)。如果为true,则返回并退出函数。我有一个通知,当函数完成它所做的操作时弹出。我遇到的问题是,如果提交按钮被垃圾邮件发送,用户可以在submitButtonDisabled从false更新为true之前多次单击该按钮,并导致在禁用之前多次请求提交。到目前为止,我的解决方案是在handleCl

我有一个按钮,当本地useState钩子为true时被禁用,当为false时被启用。我的onClick事件调用一个handleclick函数,它做的第一件事是将这个钩子设置为true(如果它还不是true)。如果为true,则返回并退出函数。我有一个通知,当函数完成它所做的操作时弹出。我遇到的问题是,如果提交按钮被垃圾邮件发送,用户可以在submitButtonDisabled从false更新为true之前多次单击该按钮,并导致在禁用之前多次请求提交。到目前为止,我的解决方案是在handleClick方法上使用setTimeout()方法,以便submitButtonDisabled状态有时间更新。这是可行的,但我的直觉告诉我这是一个糟糕的做法

我不认为状态更新需要更长的时间,但从理论上讲,如果时间超过750ms(或我设置的时间),它将发送多个请求,而我又回到了原点。我愿意接受我的解决方案,因为它目前正在工作,但如果有更好的实践,我想知道并实施它。下面是一个缩写代码的示例

const MyFunction= () => {
    const [submitButtonDisabled, setSubmitButtonDisabled] = useState(false);

    const handleClick = () => {
        if (submitButtonDisabled) {
            return;
        }
        setSubmitButtonDisabled(true);

        // do a bunch of stuff.....
        // setSubmitButtonDisabled(false) in the resolve or reject of the async call
    };

    return (        
        <div className="main-div">                                
            <button
                className="button"
                onClick={() => {
                    setSubmitButtonDisabled(true);
                    setTimeout(handleClick, 750);}}
            >{submitButtonDisabled ? "Saving..." : "Submit"}</button>
        </div>
    );
}


constmyfunction=()=>{
const[submitButtonDisabled,setSubmitButtonDisabled]=使用状态(false);
常量handleClick=()=>{
如果(提交按钮禁用){
回来
}
setSubmitButtonDisabled(true);
//做一堆事情。。。。。
//在异步调用的解析或拒绝中设置SubmitButtonDisabled(false)
};
报税表(
{
setSubmitButtonDisabled(true);
setTimeout(handleClick,750);}
>{submitButtonDisabled?“正在保存…”:“提交”}
);
}

我不完全确定为什么react无法如此快速地重新渲染组件,或者为什么用户要如此快速地单击组件,但不管有没有比直接使用timeout更好的选项来确保函数只能调用一次。以下是几个例子:

  • submitButtonDisabled
    为true时,在按钮上设置disabled

    <button className="button" onClick={handleClick} disabled={submitButtonDisabled}>
      {submitButtonDisabled ? 'Saving...' : 'Submit'}
    </button>
    
    
    {submitButtonDisabled?'Saving…':'Submit'}
    
  • 可以利用闭包确保每次渲染只能调用一次handleClick

      import React, { useRef, useState } from 'react';
    
      const MyFunction = () => {
        const [submitButtonDisabled, setSubmitButtonDisabled] = useState(false);
        let hasClickBeenCalledThisRender = false;
        const handleClick = () => {
          if (submitButtonDisabled||hasClickBeenCalledThisRender) {
            return;
          }
          hasClickBeenCalledThisRender = true;
          setSubmitButtonDisabled(true);
    
          // do a bunch of stuff.....
          // setSubmitButtonDisabled(false) in the resolve or reject of the async call
        };
    
        return (
          <div className="main-div">
            <button className="button" onClick={handleClick}>
              {submitButtonDisabled ? 'Saving...' : 'Submit'}
            </button>
          </div>
        );
      };
    
    import React,{useRef,useState}来自“React”;
    常量MyFunction=()=>{
    const[submitButtonDisabled,setSubmitButtonDisabled]=使用状态(false);
    让hasClickBeenCalledThisRender=false;
    常量handleClick=()=>{
    如果(submitButtonDisabled | |已单击已调用此渲染){
    回来
    }
    hasClickBeenCalledThisRender=true;
    setSubmitButtonDisabled(true);
    //做一堆事情。。。。。
    //在异步调用的解析或拒绝中设置SubmitButtonDisabled(false)
    };
    返回(
    {submitButtonDisabled?'Saving…':'Submit'}
    );
    };
    
  • 您可以使用ref来确保立即禁用:

    import React, { useRef, useState } from 'react';
    
    const MyFunction = () => {
      const [submitButtonDisabled, setSubmitButtonDisabled] = useState(false);
      const submitButtonDisabledRef = useRef(false);
      const handleClick = () => {
        if (submitButtonDisabledRef.current) {
          return;
        }
        submitButtonDisabledRef.current = true;
        setSubmitButtonDisabled(true);
    
        // do a bunch of stuff.....
        // setSubmitButtonDisabled(false) in the resolve or reject of the async call
        // submitButtonDisabledRef.current = false
      };
    
      return (
        <div className="main-div">
          <button className="button" onClick={handleClick}>
            {submitButtonDisabled ? 'Saving...' : 'Submit'}
          </button>
        </div>
      );
    };
    
    import React,{useRef,useState}来自“React”;
    常量MyFunction=()=>{
    const[submitButtonDisabled,setSubmitButtonDisabled]=使用状态(false);
    const submitButtonDisabledRef=useRef(false);
    常量handleClick=()=>{
    if(submitButtonDisabledRef.电流){
    回来
    }
    submitButtonDisabledRef.current=真;
    setSubmitButtonDisabled(true);
    //做一堆事情。。。。。
    //在异步调用的解析或拒绝中设置SubmitButtonDisabled(false)
    //submitButtonDisabledRef.current=false
    };
    返回(
    {submitButtonDisabled?'Saving…':'Submit'}
    );
    };
    
  • 您可以使用throttle(在本例中是由lodash提供的)来确保您的函数只能每隔x个时间(每次更新submitButtonDisabled)调用一次。(我现在意识到这应该是去盎司而不是节流阀)

    import React,{useRef,useState,usemo}来自'React';
    从“lodash”导入{throttle};
    常量MyFunction=()=>{
    const[submitButtonDisabled,setSubmitButtonDisabled]=使用状态(false);
    const handleClick=useMoom(()=>{
    回油节气门(()=>{
    如果(提交按钮禁用){
    回来
    }
    setSubmitButtonDisabled(true);
    }, 75);
    },[submitButtonDisabled]);
    返回(
    {submitButtonDisabled?'Saving…':'Submit'}
    );
    };
    
  • 您还可以使油门/去盎司的想法更易于重用,更不容易被攻击

    这里有一个useDebounce和useThrottle的示例,以及一个更正常的选项,即仅使用按钮禁用

    const{
    useRef,
    useState,
    使用备忘录,
    使用效果,
    使用回调
    }=反应;
    常数{debounce,throttle}=\uu0;
    常量MyFunction=()=>{
    const[submitButtonDisabled,setSubmitButtonDisabled]=使用状态(false);
    const[numHandleClickRuns,setNumHandleClickRuns]=useState(0);
    常数[
    提交的文件不可禁用,
    将SubmitDeBounce按钮设置为禁用状态
    ]=使用状态(假);
    const[numhandledebouncclickruns,setnumhandledebouncclickruns]=useState(
    0
    );
    常数[
    提交已禁用的按钮,
    将SubmitthRottle按钮设置为禁用
    ]=使用状态(假);
    const[numHandleThrottleClickRuns,setNumHandleThrottleClickRuns]=useState(
    0
    );
    const handleClick=事件=>{
    setSubmitButtonDisabled(true);
    setNumHandleClickRuns(num=>num+1);
    //console.log('here')
    设置超时(()=>{
    //假异步调用
    设置SubmitButtonDisabled(假);
    }, 1000);
    };
    const handledebounclick=usedbouncefn(
    事件=>{
    设置SubmitDeBounceButtonDisabled(真);
    setNumHandleDebouncClickRuns(num=>num+1);
    //console.log('here')
    设置超时(()=>{
    
    import React, { useRef, useState, useMemo } from 'react';
    import { throttle } from 'lodash';
    const MyFunction = () => {
      const [submitButtonDisabled, setSubmitButtonDisabled] = useState(false);
      const handleClick = useMemo(() => {
        return throttle(() => {
          if (submitButtonDisabled) {
            return;
          }
          setSubmitButtonDisabled(true);
        }, 75);
      }, [submitButtonDisabled]);
    
      return (
        <div className="main-div">
          <button className="button" onClick={handleClick}>
            {submitButtonDisabled ? 'Saving...' : 'Submit'}
          </button>
        </div>
      );
    };