问题
I am calling a custom NanoButton
component from my page along with an onClick
instruction to route to another page:
// Page.js
import { Component } from 'react';
import Router from 'next/router';
class Page2 extends Component {
render() {
return(
<NanoButton type="button" color="success" size="lg" onClick={() => Router.push('/about')}>About</NanoButton>
)
}
}
When the button (NanoButton
component) is clicked, I want to execute some internal code before moving on to the onClick
coming in as props. Through this internal code, I am trying to simulate the material-design ripple effect that lasts 600 milliseconds. This is how I do it:
import { Component } from 'react';
import { Button } from 'reactstrap';
class NanoButton extends Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
}
onClick(e) {
this.makeRipple(e);
this.props.onClick();
}
makeRipple(e) {
const elements = e.target.getElementsByTagName('div');
while (elements[0]) elements[0].parentNode.removeChild(elements[0]);
const circle = document.createElement('div');
e.target.appendChild(circle);
const d = Math.max(e.target.clientWidth, e.target.clientHeight);
circle.style.width = `${d}px`;
circle.style.height = `${d}px`;
const rect = e.target.getBoundingClientRect();
circle.style.left = `${e.clientX - rect.left - (d / 2)}px`;
circle.style.top = `${e.clientY - rect.top - (d / 2)}px`;
circle.classList.add('ripple');
}
render() {
return (
<Button
className={this.props.className}
type={this.props.type}
color={this.props.color}
size={this.props.size}
onClick={this.onClick}
>
{this.props.children}
</Button>
);
}
}
export default NanoButton;
So as you can see, I need the makeRipple
method to execute before this.props.onClick
. And initially, it didn't seem to doing that. However, after further testing, it turns out that the methods do run in the right order after all, except the routing (as coded in this.props.onClick
) happens instantly and the ripple animation that's styled to last 600 milliseconds doesn't get a chance to run. The CSS that makes this animation happen is:
button {
overflow: hidden;
position: relative;
}
button .ripple {
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.7);
position: absolute;
transform: scale(0);
animation: ripple 0.6s linear;
}
@keyframes ripple {
to {
transform: scale(2.5);
opacity: 0;
}
}
How do I make the this.props.onClick
run only AFTER the animation is complete? I tried setting a timeout like so:
setTimeout(this.props.onClick(), 600);
But that throws an error.
Note: I'm using NextJS for server side rendering, if that makes any difference.
回答1:
There are a lot of ways to do it, like Promise
, async/await
, etc.
But if you try setTimeout
please use
setTimeout(() => this.props.onClick(), 600);
or
setTimeout(this.props.onClick, 600);
your case:
setTimeout(this.props.onClick(), 600);
won't work because this line will pass the result of this.props.onClick()
into the first param instead of passing the whole function.
来源:https://stackoverflow.com/questions/45746939/how-to-defer-this-props-onclick-until-after-a-css-animation-is-complete