ReactJs:防止多次按下按钮

Iul*_*urt 39 javascript reactjs react-jsx

在我的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>
    );
  }

});
Run Code Online (Sandbox Code Playgroud)

我认为发生的是状态变量showUploadButton没有立即更新,React docs所说的是预期的.

我怎么能强制按钮被禁用或在点击它的瞬间全部消失?

elt*_*ami 34

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

要实现此目的,您必须在按钮元素中添加引用

<button ref="btn" onClick={this.onClickUploadFile}>Send</button>
Run Code Online (Sandbox Code Playgroud)

然后在onClickUploadFile函数上禁用该按钮

this.refs.btn.setAttribute("disabled", "disabled");
Run Code Online (Sandbox Code Playgroud)

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

.btn:disabled{ /* styles go here */}
Run Code Online (Sandbox Code Playgroud)

如果需要,请确保重新启用它

this.refs.btn.removeAttribute("disabled");
Run Code Online (Sandbox Code Playgroud)

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

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


this.btn.setAttribute("disabled", "disabled");
this.btn.removeAttribute("disabled");
Run Code Online (Sandbox Code Playgroud)

这里有一个使用您提供的代码的小例子 https://jsfiddle.net/69z2wepo/30824/

  • @KushalKumar我的观点是,这与速度无关.要求是"按钮只能被点击一次".这就是为什么我不认为debouce是这项工作的正确工具. (4认同)
  • 这让我走到了一半,但 React 团队不赞成给 ref 一个字符串值,而是使用它一个回调:https://reactjs.org/docs/refs-and-the-dom.html (3认同)
  • @KushalKumar如何对这个问题进行防抖动处理?对于一次仅解决这种问题的速率应该是多少? (2认同)

cqu*_*zel 24

解决方案是在进入处理程序后立即检查状态.React保证在浏览器事件边界刷新交互事件(例如click)中的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>
Run Code Online (Sandbox Code Playgroud)

  • 这是最干净的方法,应该是公认的答案。 (3认同)

zvo*_*ona 17

测试工作: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);
Run Code Online (Sandbox Code Playgroud)

  • 这不会解决问题,因为状态更新被React去抖.因此,`this.state.isButtonDisabled`总是会延迟获得'false'值.快速连续点击两次仍会注册2个onClick事件. (11认同)
  • @Awol React保证在浏览器事件边界刷新交互事件(例如click)中的setState.请参阅下面的答案.如果在事件处理程序中更改了读取或设置状态,则不会出现问题. (7认同)

slo*_*nzo 9

您可以尝试使用React Hooks来设置Component State

import React, { useState } from 'react';

const Button = () => {
  const [double, setDouble] = useState(false);
  return (
    <button
      disabled={double}
      onClick={() => {
        // doSomething();
        setDouble(true);
      }}
    />
  );
};

export default Button;
Run Code Online (Sandbox Code Playgroud)

确保您使用的^16.7.0-alpha.xreact和 的版本或更高版本react-dom

希望这对你有帮助!

  • 这不会立即禁用该按钮。您依赖 setter 来生效,这需要重绘组件,因此它不会是瞬时的。 (3认同)
  • 那么这个按钮将永远保持禁用状态,或者直到刷新页面或呈现组件为止?这看起来不太理想? (2认同)

Vaj*_*ecz 6

如果您在 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}
        />
    )
}

Run Code Online (Sandbox Code Playgroud)

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

我们基本上使用在 onClick 执行期间禁用的额外行为来扩展 Button 组件。执行此操作的步骤:

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

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


Jun*_*Nam 5

如果您愿意,只需阻止提交即可。

怎么用 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>
Run Code Online (Sandbox Code Playgroud)