Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sequential setState calls not working as expected

I am creating a component with an animation that occurs with a css class toggle. Sandbox of the example here.

The css class is applied conditionaly against the transitioned field, so we should get an animation when the transtioned field goes form false to true.

Problem:

The animation doesn't happen in the case where the state if modified like this :

animateWithoutST = () => {
    this.setState({transitioned: false}, 
    () => this.setState({transitioned: true}))
  }

But it works if it the second setState is called within a setTimeout callback like this:

 animateWithST = () => {
    this.setState({ transitioned: false },
    () => {
      setTimeout(() => this.setState({ transitioned: true }))
    }
    )
  }

Why isn't animateWithoutST working as expected although my component is rendering in the right order ?

like image 352
Lev Avatar asked Jan 31 '18 17:01

Lev


1 Answers

This looked definitely bizarre and I had to dig into it until I understood what is happening.

So, yeah without the setTimeout it doesn't work, not even in the componentDidUpdate method and there is an explanation: you are changing the state, and it is updated, and render is called twice BUT because of browser optimization we don't see the animation happening: "browsers are not re-rendering stuff that changed in the same animation frame".

When you use the setTimeout you are forcing the 2nd state update to go into the next animation frame and voila you see the animation. Even with the current timeout value set to 0, it might not work on some browsers, but if you set the value to > 16ms aprox, it prob will work always (you need a value greater than an animation frame).

You can also use requestAnimationFrame, twice to assure your both state updates fall into different animation frames, check it here.

I found all this info in this article, check it because it is extremely well explained. Does now make sense to you?

like image 165
elbecita Avatar answered Sep 22 '22 17:09

elbecita