ReactJs:防止多次按下按钮

ReactJs: Prevent multiple times button press

本文关键字:按钮 ReactJs      更新时间:2023-09-26

在我的 React 组件中,我有一个按钮,用于在单击时通过 AJAX 发送一些数据。我只需要第一次发生,即在第一次使用后禁用按钮。

我是如何尝试这样做的:

var UploadArea = React.createClass({
  getInitialState() {
    return {
      showUploadButton: true
    };
  },
  disableUploadButton(callback) {
    this.setState({ showUploadButton: false }, callback);
  },
  // This was simpler before I started trying everything I could think of
  onClickUploadFile() {
    if (!this.state.showUploadButton) {
      return;
    }
    this.disableUploadButton(function() {
      $.ajax({
        [...]
      });
    });
  },
  render() {
    var uploadButton;
    if (this.state.showUploadButton) {
      uploadButton = (
        <button onClick={this.onClickUploadFile}>Send</button>
      );
    }
    return (
      <div>
        {uploadButton}
      </div>
    );
  }
});

我认为发生的事情是状态变量showUploadButton没有立即更新,React 文档说这是预期的。

我怎样才能强制按钮在被单击的那一刻被禁用或完全消失?

解决方案是在进入处理程序后立即检查状态。React 保证交互式事件(如点击)中的 setState 在浏览器事件边界处被刷新。参考: https://github.com/facebook/react/issues/11171#issuecomment-357945371

// In constructor
this.state = {
    disabled : false
};

// Handler for on click
handleClick = (event) => {
    if (this.state.disabled) {
        return;
    }
    this.setState({disabled: true});
    // Send     
}
// In render
<button onClick={this.handleClick} disabled={this.state.disabled} ...>
    {this.state.disabled ? 'Sending...' : 'Send'}
<button>

您可以做的是在单击后禁用按钮并将其保留在页面中(不可单击的元素)。

要实现这一点,您必须向按钮元素添加一个 ref

<button ref="btn" onClick={this.onClickUploadFile}>Send</button>

然后在点击上传文件功能上禁用按钮

this.refs.btn.setAttribute("disabled", "disabled");

然后,您可以相应地设置禁用按钮的样式,以便通过以下方式向用户提供一些反馈

.btn:disabled{ /* styles go here */}

如果需要,请确保使用

this.refs.btn.removeAttribute("disabled");

更新:在 React 中处理 refs 的首选方法是使用函数而不是字符串。

<button 
  ref={btn => { this.btn = btn; }} 
  onClick={this.onClickUploadFile}
>Send</button>

this.btn.setAttribute("disabled", "disabled");
this.btn.removeAttribute("disabled");

更新:使用反应钩子

import {useRef} from 'react';
let btnRef = useRef();
const onBtnClick = e => {
  if(btnRef.current){
    btnRef.current.setAttribute("disabled", "disabled");
  }
}
<button ref={btnRef} onClick={onBtnClick}>Send</button>

下面是使用您提供的代码的小示例https://jsfiddle.net/69z2wepo/30824/

测试为工作:http://codepen.io/zvona/pen/KVbVPQ

class UploadArea extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      isButtonDisabled: false
    }
  }
  uploadFile() {
    // first set the isButtonDisabled to true
    this.setState({
      isButtonDisabled: true
    });
    // then do your thing
  }
  render() {
    return (
      <button
        type='submit'
        onClick={() => this.uploadFile()}
        disabled={this.state.isButtonDisabled}>
        Upload
      </button>
    )
  }
}
ReactDOM.render(<UploadArea />, document.body);

你可以尝试使用 React Hooks 来设置组件状态。

import React, { useState } from 'react';
const Button = () => {
  const [double, setDouble] = useState(false);
  return (
    <button
      disabled={double}
      onClick={() => {
        // doSomething();
        setDouble(true);
      }}
    />
  );
};
export default Button;

确保您使用的是^16.7.0-alpha.x版本或更高版本的 reactreact-dom

希望对您有所帮助!

如果你在onClick期间禁用按钮,你基本上会得到这个。一个干净的方法是:

import React, { useState } from 'react';
import Button from '@material-ui/core/Button';
export default function CalmButton(props) {
    const [executing, setExecuting] = useState(false);
    const {
        disabled,
        onClick,
        ...otherProps
    } = props;
    const onRealClick = async (event) => {
        setExecuting(true);
        try {
            await onClick();
        } finally {
            setExecuting(false);
        }
    };
    return (
        <Button
            onClick={onRealClick}
            disabled={executing || disabled}
            {...otherProps}
        />
    )
}

在这里看到它的实际效果:https://codesandbox.io/s/extended-button-that-disabled-itself-during-onclick-execution-mg6z8

我们基本上扩展了按钮组件,增加了在onClick执行期间被禁用的额外行为。执行此操作的步骤:

  1. 创建本地状态以在执行时捕获
  2. 提取我们篡改的属性(禁用,onClick)
  3. 通过设置执行状态扩展单击操作
  4. 使用我们覆盖的 onClick 渲染按钮,并扩展禁用

注意:您应该确保原始的onClick操作是异步的,也就是它返回一个承诺。

如果你愿意,只需阻止提交。

使用lodash.js debounce怎么样

将突发事件(如击键)分组为一个事件。

https://lodash.com/docs/4.17.11#debounce

<Button accessible={true}
    onPress={_.debounce(async () => {
                await this.props._selectUserTickets(this.props._accountId)
    }, 1000)}
></Button>

通过使用 event.target ,您可以禁用单击的按钮。创建时使用箭头函数并调用函数onClick 。不要忘记在参数中传递事件。

查看我的代码笔

这是代码:

class Buttons extends React.Component{
  constructor(props){
    super(props)
    this.buttons = ['A','B','C','D']
  }
  disableOnclick = (e) =>{
    e.target.disabled = true
  }
  render(){
    return(
     <div>
        {this.buttons.map((btn,index) => (
          <button type='button' 
            key={index} 
            onClick={(e)=>this.disableOnclick(e)}
            >{btn}</button>
        ))}
      </div>
  )}
}
ReactDOM.render(<Buttons />, document.body);
const once = (f, g) => {
    let done = false;
    return (...args) => {
        if (!done) {
            done = true;
            f(...args);
        } else {
            g(...args);
        }
    };
};
const exampleMethod = () => console.log("exampleMethod executed for the first time");
const errorMethod = () => console.log("exampleMethod can be executed only once")
let onlyOnce = once(exampleMethod, errorMethod);
onlyOnce();
onlyOnce();

输出

exampleMethod executed for the first time
exampleMethod can be executed only once

您可以在 onClick 回调中获取元素引用并从那里setAttribute,例如:

      <Button
        onClick={(e) => {
          e.target.setAttribute("disabled", true);
          this.handler();
        }}            
      >
        Submit
      </Button>

保持简单和内联:

<button type="submit"
        onClick={event => event.currentTarget.disabled = true}>
    save
</button>

但!这也将禁用按钮,当表单校准失败时!因此,您将无法重新提交。

在这种情况下,二传手更好。

此修复了在窗体onSubmit中设置禁用:


// state variable if the form is currently submitting
const [submitting, setSubmitting] = useState(false);
// ...
return (
<form onSubmit={e => {
                setSubmitting(true); // create a method to modify the element
            }}>
    <SubmitButton showLoading={submitting}>save</SubmitButton>
</form>
);

按钮看起来像这样:

import {ReactComponent as IconCog} from '../../img/icon/cog.svg';
import {useEffect, useRef} from "react";
export const SubmitButton = ({children, showLoading}) => {
    const submitButton = useRef();
    useEffect(() => {
        if (showLoading) {
            submitButton.current.disabled = true;
        } else {
            submitButton.current.removeAttribute("disabled");
        }
    }, [showLoading]);
    return (
        <button type="submit"
                ref={submitButton}>
            <main>
                <span>{children}</span>
            </main>
        </button>
    );
};

另一种方法可能是这样的:

<button onClick={this.handleClick} disabled={isLoading ? "disabled" :""}>Send</button>

我的方法是,如果处理中的事件不执行任何内容。

class UploadArea extends React.Component {
constructor(props) {
super(props)
this.state = {
  onProcess:false
   }
}
uploadFile() {
 if (!this.state.onProcess){
   this.setState({
     onProcess: true
   });
   // then do your thing
   this.setState({
     onProcess: false;
   });
 }    
}
render() {
  return (
    <button
      type='submit'
      onClick={() => this.uploadFile()}>
      Upload
    </button>
   )
  }
}
ReactDOM.render(<UploadArea />, document.body);

尝试使用以下代码:

class Form extends React.Component {
    constructor() {
        this.state = {
            disabled: false,
        };
    }
    handleClick() {
        this.setState({
            disabled: true,
        });
        if (this.state.disabled) {
            return;
        }
        setTimeout(() => this.setState({ disabled: false }), 2000);
    }
    render() {
        return (
            <button type="submit" onClick={() => this.handleClick()} disabled={this.state.disabled}>
                Submit
            </button>
        );
    }
}
ReactDOM.render(<Form />, document.getElementById('root'));

如果仍然有人面临此类问题,解决方案比创建自定义组件等要容易得多......

  1. 设置一个名为"默认禁用"的状态值 false。
  2. 将其分配给按钮的禁用属性。
  3. 在 onPress 中首先将其设置为 true,然后做你的事情....
  4. 然后在组件的 un mount 上将其设置为 false...
function MyClickable() {
    const [disabled,setDisabled] = useState(false)
useEffect(() => {
return () => setDisabled(false)
},[])
    const onPress  = useCallback(() => {
                         setDisabled(true);
                         // do your stuff
                    },[]);
     <TouchableOpacity disabled={disabled} onPress={onPress}>
          // your things
     </TouchableOpacity>

尝试使用此代码

<button 
    onClick={async (e) => {
    e.currentTarget.disabled = true;
    await onClickUploadFile();
    e.currentTarget.disabled = false;
}}>
    Upload
</button>