
Debounce and avoid multiple clicks event generation on React.js…
There are some instances where you need to debounce and avoid multiple clicks/taps on a button so that it will not generate the same action chain immediately with a consecutive click. An example would be an application with a touchscreen. If you click a button rapidly, that event will be generated more than once. As a solution, most of the time devs would block the UI until the action chain is completed. But this would be a bad experience if the user is blocked for any other interactions. A typical example can be a fetch call to update the state and if the invocation is asynchronous it could be causing more inconvenience.
How to debounce and avoid multiple clicks
What I did was to create a stateful component with react.js and use debounce
function of Lodash(https://lodash.com/docs/4.17.4#debounce). This will debounce and avoid multiple clicks which are generated after the first click/tap for a limited time. With leading: true, it will define that the first click will be executed all the trailing invocations are discarded.
I created a ClickableComponent
class which could be used for any component with an onClick
parameter.
class ClickableElement extends React.Component { static INTERVAL = 1000; constructor(props) { super(props); this.state = {}; } componentWillReceiveProps(nextProps) { const { onClick, disabled } = nextProps; this.setState({ onClick, disabled, }); } onClickDebounced(e) { const { onClick, disabled } = this.state; if (!disabled && _.isFunction(onClick)) { onClick(e); } } componentWillMount() { this.componentWillReceiveProps(this.props); const { clickWait } = this.props; const wait = clickWait || Button.INTERVAL; this.onElementClicked = _.debounce(this.onClickDebounced, wait, { maxWait:wait, leading: true, trailing: false, }); } }
Note that I have used Lodash as _
in the code. Now you can use it in any component where you would invoke onClick
function.
export class TouchButton extends ClickableElement { render() { const otherProps = _.omit(this.props, ['onClick', 'type']); return ( <button onClick={e => this.onElementClicked(e)} type="button" {...otherProps} >{otherProps.value}</button> ); } }
See the Pen React Debounce Button by Sandaruwan Nanayakkara (@sandaruny) on CodePen.
Finally the click debouncing time is in milliseconds and default wait time of one second has set with INTERVAL
static property. And if you want to override the waiting time for the clicks, you can set the wait
time as desired.
<TouchButton clickWait={2000} onClick={() => doSomething()} value="Something" />
This is working great and if you want to generate an event for once, you can slightly modify the Lodash debounce function parameters.
If you have simpler approach please do give a feedback.