Create tight button effect

1

I have the following component in React:

import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);

    this.state = {
      count: parseInt(this.props.value)
    };

    this.inc = this.inc.bind(this);
    this.dec = this.dec.bind(this);
  }

  inc() {
    this.setState({ count: this.state.count + 1 });
  }

  dec() {
    this.setState({ count: this.state.count - 1 });
  }

  render() {
    return (
      <div>
        <p>
          O valor inicial é: <code>{this.props.value}</code>.
        </p>
        <div>
          O valor <strong>atual</strong> é: <code>{this.state.count}</code>.
        </div>
        <div>
          <button onClick={this.inc}>Incrementar</button>
          <button onClick={this.dec}>Decrementar</button>
        </div>
      </div>
    );
  }
}

module.exports = Counter;

It basically has a number, which, at the push of a button, is incremented by one. Thus, with each click, the value increases by one.

How do I keep the button pressed (holding down the left mouse button), and keep increasing the value (until I stop pressing the left button)?

    
asked by anonymous 07.02.2018 / 21:52

1 answer

2

Define a variable in the constructor method, for example:

this.interval = null;

It will save the timer setInterval , now create a method to clear the timer:

clear() {
    clearInterval(this.interval);
    this.interval = null;
}

In the constructor method bind the new method:

this.clear = this.clear.bind(this);

You should make the following changes to the methods inc and dec :

inc() {
    if (this.interval === null) {
        this.interval = setInterval(this.inc, 100);
    }
    this.setState({ count: this.state.count + 1 });
}

dec() {
    if (this.interval === null) {
        this.interval = setInterval(this.dec, 100);
    }
    if (this.state.count > 0) {
        this.setState({ count: this.state.count - 1 });
    }
}

Change the onClick events to onMouseDown and add the onMouseUp event which will execute the clear method, thus giving the code:

<button onMouseUp={this.clear} onMouseDown={this.inc}>Incrementar</button>
<button onMouseUp={this.clear} onMouseDown={this.dec}>Decrementar</button>

Example running

class Counter extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      count: parseInt(this.props.value)
    };
    this.interval = null;
    this.clear = this.clear.bind(this);
    this.inc = this.inc.bind(this);
    this.dec = this.dec.bind(this);
  }

  inc() {
    if (this.interval === null) {
      this.interval = setInterval(this.inc, 100);
    }
    this.setState({ count: this.state.count + 1 });
  }

  dec() {
    if (this.interval === null) {
      this.interval = setInterval(this.dec, 100);
    }
    if (this.state.count > 0) {
      this.setState({ count: this.state.count - 1 });
    }
  }

  clear() {
    clearInterval(this.interval);
    this.interval = null;
  }

  render() {
    return (
      <div>
        <p>
          O valor inicial é: <code>{this.props.value}</code>.
        </p>
        <div>
          O valor <strong>atual</strong> é: <code>{this.state.count}</code>.
        </div>
        <div>
          <button className="inc" onMouseUp={this.clear} onMouseDown={this.inc}>Incrementar</button>
          <button className="dec" onMouseUp={this.clear} onMouseDown={this.dec}>Decrementar</button>
        </div>
      </div>
    );
  }
}


ReactDOM.render(<Counter value="0" />, document.getElementById('app'));
button {
  border: 0;
  color: #fff;
  cursor: pointer;
  font-family: 'Verdana', sans-serif;
  font-size: 1em;
  padding: 8px;
  text-transform: uppercase;
}

.inc {
  background: #388E3C;
  margin-right: 14px;
}
.dec {
  background: #E57373;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
  

If you prefer you can see it working at codesandbox.io

Reference

07.02.2018 / 23:48