ReactJs: Предотвращение многократного нажатия кнопки

В моем компоненте 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 docs.

Как я могу заставить кнопку отключиться или уйти вместе во время клика?

Ответ 1

Что вы можете сделать, это сделать кнопку отключенной после нажатия кнопки и оставить ее на странице (не активируемый элемент).

Для достижения этого вы должны добавить ссылку на элемент кнопки

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

а затем на функцию onClickUploadFile отключить кнопку

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

Затем вы можете соответственно стилизовать отключенную кнопку, чтобы дать пользователю обратную связь с

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

При необходимости обязательно включите его

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

Обновление: предпочтительный способ обработки ссылок в React - использовать функцию, а не строку.

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


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

Вот небольшой пример с использованием кода, который вы предоставили https://jsfiddle.net/69z2wepo/30824/

Ответ 2

Решение состоит в том, чтобы проверить состояние сразу после входа в обработчик. 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>

Ответ 3

Проверено как работающее: 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);

Ответ 4

Вы можете попробовать использовать 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 версию react и react-dom.

Надеюсь, это поможет вам!

Ответ 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>

Ответ 6

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