In the Material UI Transitions doc, there are examples where a button triggers a transition. I have a case where a button triggers a state change and I want the former data to transition out and then the new data to transition in. The only way I have found to do this is with setTimeout
. Is there a better way?
In CodeSandbox
import React from "react";
import Slide from "@material-ui/core/Slide";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
const words = ["one", "two", "three"];
const transitionDuration = 500;
class TransitionCycle extends React.Component {
state = {
activeIndex: 0,
elementIn: true
};
onClick = () => {
this.setState({
elementIn: false
});
setTimeout(() => {
this.setState({
elementIn: true,
activeIndex: (this.state.activeIndex + 1) % words.length
});
}, transitionDuration);
};
render() {
const { activeIndex, elementIn } = this.state;
return (
<div>
<Button onClick={this.onClick}>Cycle</Button>
<Slide
in={this.state.elementIn}
timeout={transitionDuration}
direction="right"
>
<Typography variant="h1">{words[this.state.activeIndex]}</Typography>
</Slide>
</div>
);
}
}
export default TransitionCycle;
Is this the best way to do back to back transitions in Material UI? It feels odd to use setTimeout
.
In the Material UI Transitions doc, there are examples where a button triggers a transition. I have a case where a button triggers a state change and I want the former data to transition out and then the new data to transition in. The only way I have found to do this is with setTimeout
. Is there a better way?
In CodeSandbox
import React from "react";
import Slide from "@material-ui/core/Slide";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
const words = ["one", "two", "three"];
const transitionDuration = 500;
class TransitionCycle extends React.Component {
state = {
activeIndex: 0,
elementIn: true
};
onClick = () => {
this.setState({
elementIn: false
});
setTimeout(() => {
this.setState({
elementIn: true,
activeIndex: (this.state.activeIndex + 1) % words.length
});
}, transitionDuration);
};
render() {
const { activeIndex, elementIn } = this.state;
return (
<div>
<Button onClick={this.onClick}>Cycle</Button>
<Slide
in={this.state.elementIn}
timeout={transitionDuration}
direction="right"
>
<Typography variant="h1">{words[this.state.activeIndex]}</Typography>
</Slide>
</div>
);
}
}
export default TransitionCycle;
Is this the best way to do back to back transitions in Material UI? It feels odd to use setTimeout
.
2 Answers
Reset to default 1It's possible to use CSS transitions directly and to use an event listener instead of setTimeout to detect when the transition has happened, Mozilla provides documentation on that here: https://developer.mozilla/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions#Detecting_the_start_and_pletion_of_a_transition
class MyComponent extends React.Component {
updateTransition = () => {
this.setState({
elementIn: true,
activeIndex: (this.state.activeIndex + 1) % words.length
});
}
ponentDidMount() {
elementRef.addEventListener("transitionend", updateTransition, true);
}
}
Don't forget to add the event listener on mounting and remove it on unmounting the ponent.
I think conditionally render all 3 Slides
could solve your problem, here.
I also checked the source codes of Transition
and it also uses setTimeout
in the end, so I think it's not that "weird" to use it, but if the ponent already wraps the low-level api (I mean setTimeout) for us then we surely don't want to use it.
Edit:
As OP's ment, I found that I misread his example and didn't notice the out transition, so I modified my codes to meet the requirement. Now the previous Slide
exits pletely, then the next one enters. Everything is done by the ponent's designed props. (Still, the underlying Transition
source codes are just wrapping the Rudolf Olah's method, but I just try to use only the designed props)
However, by only using Transition
's props, I think it's impossible to achieve the "delay" entering what OP did using setTimeout
, so if OP still wants to have that small delay before "Two" enters, you might still have to use setTimeout
.