Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS Transitions don't survive React Component changing inner DOM structure

I have illustrated the problem in this CodePen

const Component = ({ structure }) => {
  switch (structure) {
    case 'nested': 
      return (
        <div>
          <AnimatedComponent />
      </div>
     );
    case 'flat': 
      return 
        <AnimatedComponent />
      ;
  }
};

There's some logic in AnimatedComponent that changes the styling of the Component in an animated fashion, e.g. change the background color from black to red over a duration of 1 second. The animation is started by changing a color class on AnimatedComponent. There is CSS to handle the animation given the changed class.

When changing the DOM structure from nested to flat, the HTML element is destroyed and recreated, the transition starting state is lost (aka the browser doesn't know which class was set before because the element was newly created).

What I want React to do is to change the DOM structure with moving elements in new positions, not destroying and recreating them.

Is this possible?

I tried to use the key props on <AnimatedComponent />, but it only fixes the flash of DOM change. Animation is skipped. See Codepen. Thanks Thomas Rooney for this suggestion.

Can I tell React to apply the class changes just one tick after the position of the DOM element was changed?

like image 824
Tobias Mühl Avatar asked Mar 28 '26 17:03

Tobias Mühl


1 Answers

Can I tell React to apply the class changes just one tick after the position of the DOM element was changed?

Yes, this is precisely what the setTimeout function is for. Copying your second example, where you fixed the flickering, wrapping your color action dispatch with setTimeout (with no time value, which defaults to 0), seems to fix your issue.

onColorClick: () => {
  setTimeout(() => { 
    dispatch({type: 'TOGGLE_COLOR'})
  })
},

codepen

Update: I've noticed it's a bit more reliable to add some time before the color change (second argument in setTimeout, (fn, ms). I believe this is because setState is also happening asynchronously.

onColorClick: () => {
  setTimeout(() => { 
    dispatch({type: 'TOGGLE_COLOR'})
  }, 100) <-- play around with this value
},
like image 180
azium Avatar answered Mar 30 '26 05:03

azium



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!