Reputation: 288
I have this ReactJS class :
import React from 'react';
export default class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
status: 'main',
};
}
applyTransition() {
this.setState({
status: 'leaving',
}, () => {
setTimeout(() => {
this.setState({
status: 'entering'
}, () => setTimeout(() => {
this.setState({
status: 'main',
});
}, 1000));
}, 1)
});
}
handleClick() {
this.applyTransition();
}
computeStyle() {
switch (this.state.status) {
case 'leaving':
return {
transform: 'translate(-100%)',
};
case 'entering':
return {
transform: 'translate(0%)',
transition: 'transform 1s',
};
case 'main':
return {
transform: 'translate(0%)',
};
}
}
render() {
const style = this.computeStyle();
return (
<div>
<div style={_.merge({}, style, {
display: 'flex',
flexOrientation: 'row',
})}>
<div>1</div>
<div>2</div>
<div>3</div>
</div>
<button onClick={() => this.handleClick()}>Click</button>
</div>
);
}
}
My workflow is the following, I have a "main" state in which the content is displayed normally, I have a "beforeTransition" state in which I want the content to be translated to the left and a "transition" in which I want the content to come back in place with a CSS transition.
It seems that react does not update the DOM properly if I do not use a timeout of 1 ms. Consequently, the transition does not work. Why?
So how do I ensure that my CSS transition workflow is completed? I WANT that DOM to be updated and rendered properly at each changes of my state.status variable.
I don't want to use ReactCSSTransitionGroup because I want to understand how I can create some custom CSS transitions from scratch.
Upvotes: 0
Views: 181
Reputation: 774
Even though I'm not super familiar with the way of how the rendering queue in browsers works, I assume that you cannot assign contrary css properties with no delay between them. Like transition to left - then to right again.
And it probably has nothing to with React per se.
Look here: https://jsbin.com/geqogeqifa/edit?html,output
EDIT: (heavily guessing)
As rendering the output and JS are using the same event queue in the browsers, no re-rendering happens between your "leaving" and "entering" css property assignment – which causes the last property override the first one even before the first one was rendered.
So my guess is, by using a timeout, you insert another event in the event queue, which is called after a previous render event happened…
Pseudo Event Queue:
Without timeout:
Event(JS): css(leaving), css(entering)
Event(Render) // renders only entering
With timeout:
Event(JS): css(leaving), setTimeOut(css(entering))
Event(Render) // renders leaving
Event(timeOut): css(entering)
Event(Render) // renders entering
Upvotes: 1
Reputation: 3536
If you are just trying to animate translating an existing element (which appears to be the case based on your code) then this would be a much simpler approach:
constructor() {
super();
this.state = {enter: false};
}
handleClick() {
this.setState({
enter: true
});
}
computeStyle(enter) {
return {
transform: enter ? 'translate(0%)' : 'translate(-100%)',
transition: 'transform 1s'
};
}
render() {
const style = this.computerStyle(this.state.enter);
// divs and stuff with your style
<button onClick={this.handleClick} />
}
Upvotes: 0