October 23, 2019
In order to provide a good user experience, user should recieve fast feedback when they click a button.
Sometimes network calls can take too long, so we have to display a something to tell user that something is happening.
Here is a simple react component that will accomplish this, and is easily reusable.
// example.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import LoadingButton from './loadingButton';
export default class Example extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
}
this.spinner = this.spinner.bind(this);
this.onClick = this.onClick.bind(this);
}
render() {
return (
<LoadingButton loading={this.state.loading}
onClick={() => this.setState({ loading: !this.state.loading }) }
/>
)
}
}
// loadingButton.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import './loadingButton.scss'
class LoadingButton extends Component {
constructor(props) {
super(props);
this.spinner = this.spinner.bind(this);
this.onClick = this.onClick.bind(this);
}
spinner() {
if (this.props.loading) {
return (
<svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
width="40px" height="40px" viewBox="0 0 40 40" enableBackground="new 0 0 40 40">
<path opacity="0.2" fill="#000" d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946
s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634
c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z"/>
<path fill="#000" d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0
C22.32,8.481,24.301,9.057,26.013,10.047z">
<animateTransform attributeType="xml"
attributeName="transform"
type="rotate"
from="0 20 20"
to="360 20 20"
dur="0.5s"
repeatCount="indefinite"/>
</path>
</svg>
)
}
}
onClick() {
if (this.props.onClick) {
this.props.onClick();
}
}
render() {
if (this.props.onClick) {
return (
<button className="loading-button" onClick={this.onClick}>
{this.spinner()}
{this.props.children}
</button>
)
}
return (
<button type="submit" className="loading-button">
{this.spinner()}
{this.props.children}
</button>
)
}
}
LoadingButton.propTypes = {
loading: PropTypes.bool.isRequired,
onClick: PropTypes.func,
};
export default LoadingButton;
// loadingButton.scss
.loading-button {
margin: 0 0 2em;
height: 100px;
width: 20%;
text-align: center;
padding: 1em;
margin: 0 auto 1em;
display: inline-block;
vertical-align: top;
position: relative;
svg {
margin: 6px 10px;
vertical-align: bottom;
position: absolute;
left: 0px;
path,
rect{
fill: #8ad7dd;
}
}
}