Search code examples
javascripthtmlcssreactjsreact-transition-group

React: Calling Render() during animation. What happens?


I want to know how React handles a Render that is called during a component's animation. In the below example, a component is rerendered

Say there is a state change to the component during the component's animation, and so the component is re-rendered. Will react replace the physical DOM or will it recognize that the component is in mid-animation? Here is what I think will happen

Step 1: Component Mounts The component is mounted to the physical DOM for the first time. The component's animation lasts 60 seconds. The component has a change state timer that will go off in 30 seconds. Meanwhile, react saves the virtual DOM at the time of mounting.

Step 2: State change is triggered and the component re-renders After 30 seconds, a state change will occur in the parent, and the component will be re-render. At this point the component is in mid animation, and using react-transition-group, the "className-active" css class is being applied to the child. React will now compare the present virtual DOM with the older virtual DOM. The virtual DOMs are different as the child now has the active class applied to it (as opposed to the "enter" class). As a result, react will insert the updated component into the physical DOM (even though the physical DOM does not need to be updated!). Therefore, the screen will flicker...

Here is the code describing the scenario above

import React from 'react'
import CSSTransition from 'react-transition-group'
                                                                                                                                                                                                                     ```
class ExampleComponent extends React.Component {
      constructor(props) {
           super(props);
           this.state = {reRender : false};
           setTimeout(() => {this.setState({reRender: true})}, 30000) 
           /* 30,000 ms is 30 seconds. 
              Set state will fire in 30 seconds, and the parent component will 
             rerender itself and the     
           */
     }
      render()  {
          return (
                <CSSTransition
            appear = {true}
            in = {true}
            classNames = 'test'
            timeout = {60000}>
                <span> test </span>
        </CSSTransition>
          )

      }

}

Here are the relevant css classes

.test-appear, test-enter{
       opacity : 1;
}
.test-appear-active, .test-enter-active {
      opacity: 0; 
      transition: opacity; 
      transition-duration: 60000;
}
.test-appear-done, .test-enter-done {
      opacity: 0;    
}

Given this code, I would like to be walked step by step what happens in the react lifecycle, and the virtual DOM. Will the physical DOM be updated after 30 seconds or will react recognize it is in mid animation? How is the virtual DOM saving previous state?


Solution

  • On this case CSSTransition is keeping internal state to know in which phase of the animation it is.

    React does not reset the state of the CSSTransition instance because it knows it refers to the same element (React relies on the type of component and position on the tree to decide if it is the same element, or on the key prop when defined)

    Because the internal state of CSSTransition is the same it's render method renders the same css class before and after the state change on your component.

    See your example it working without flicker https://codesandbox.io/s/hopeful-shaw-c9ldr

    CSSTransition might change the state in response to a change in any of the props you pass to it (which in this case does not even occur) but that's dependant on the CSSTransition implementation.

    Finally, if you passed a different key to CSSTransition it would reset the animation as React would consider it a new component, so would unmount the previous one and mount a new one, with a new internal state.

    see the example with the animation reseting here: https://codesandbox.io/s/jolly-maxwell-2ihkf