Author avatar

Vivek Kumar

ReactJS: Transitions

Vivek Kumar

  • Jun 6, 2019
  • 12 Min read
  • 159 Views
  • Jun 6, 2019
  • 12 Min read
  • 159 Views
reactjs-transition

Introduction

When we look around for effective and reliable transition components, ReactJS transition is one of the few with a worth-mentioning track record of superlative results. It is a transition component which is inspired by the acclaimed ng-animate library. The library, which is highly resourceful, if you are applying CSS animations or transitions. It is, basically, because of the fact that it has been set on the transition component that comprises of all its properties.

The Transition

It is significant to understand that ReactJS Transition executes a couple of class names amidst appear, the enter and the exit states of transition. In order to successfully activate the ReactJS transition, the first class is implemented and, thereafter, a second *-activeclass. After the completion of the transition, add a matching *-done to continue the transition state.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function App( ) {
  const [ inProp, setInProp ] = useState( false );
  return (
    < div >
      < CSSTransition in = { inProp } timeout = { 200 } classNames = "my-node" >
        < div >
          { "I'll receive my-node-* classes" }
        </ div >
      </ CSSTransition >
      < button type = "button" onClick = { () => setInProp( true ) } >
        Click to Enter
      </ button >
    </ div>
  );
}
javascript

Here, it is critical to understand that when inprop is being set to true, it is the child component which will foremost acquire class example-enter. It is later that example-enter-active is incorporated into next tick.

ReactJS CSS Transition compels a re-flow prior to adding the example-enter-active. It is one of the most acclaimed and widely used tricks, due to the fact that it permits us to have the transition in between the example-enter and example-enter-active, despite of the fact that they were incorporated just one after another. It is noteworthy that this is the step which eventually makes it feasible for all of us to animate the Appearance.

The process can be properly understood by the codes mentioned below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.my-node-enter {
  opacity: 0;
}
.my-node-enter-active {
  opacity: 1;
  transition: opacity 200ms;
}
.my-node-exit {
  opacity: 1;
}
.my-node-exit-active {
  opacity: 0;
  transition: opacity 200ms;
}
javascript

*-active classes hereby represent the type of styles you wish to animate in. An example can be well understood by the following code:

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import { Container, Button, Alert } from 'react-bootstrap';
import { CSSTransition } from 'react-transition-group';

import './styles.css';

function Example() {
  const [showButton, setShowButton] = useState(true);
  const [showMessage, setShowMessage] = useState(false);
  return (
    <Container style={{ paddingTop: '2rem' }}>
      {showButton && (
        <Button
          onClick={() => setShowMessage(true)}
          size="lg"
        >
          Show Message
        </Button>
      )}
      <CSSTransition
        in={showMessage}
        timeout={300}
        classNames="alert"
        unmountOnExit
        onEnter={() => setShowButton(false)}
        onExited={() => setShowButton(true)}
      >
        <Alert
          variant="primary"
          dismissible
          onClose={() => setShowMessage(false)}
        >
          <Alert.Heading>
            Animated alert message
          </Alert.Heading>
          <p>
            This alert message is being transitioned in and
            out of the DOM.
          </p>
          <Button onClick={() => setShowMessage(false)}>
            Close
          </Button>
        </Alert>
      </CSSTransition>
    </Container>
  );
}

ReactDOM.render(
  <Example />,
  document.getElementById('root')
);
javascript

styles.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.alert-enter {
  opacity: 0;
  transform: scale(0.9);
}
.alert-enter-active {
  opacity: 1;
  transform: translateX(0);
  transition: opacity 300ms, transform 300ms;
}
.alert-exit {
  opacity: 1;
}
.alert-exit-active {
  opacity: 0;
  transform: scale(0.9);
  transition: opacity 300ms, transform 300ms;
}
css

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
{
  "name": "csstransition-component",
  "version": "1.0.0",
  "description": "",
  "keywords": [],
  "main": "index.js",
  "dependencies": {
    "react": "16.8.4",
    "react-bootstrap": "1.0.0-beta.6",
    "react-dom": "16.8.4",
    "react-transition-group": "2.7.0"
  }
}
json

index.html

1
<div id="root"></div>
html

Props Here, considering all types of props from the <Transition> until and unless noted otherwise.

classNames The transition animation termed as classNames is implemented onto the components whenever it enters, exits, or otherwise has completed the transition. Here, a solo name can be rendered and this name can be suffixed on each and every stage.

For instance:

1
classNames = "fade" applies fade-enter, fade-enter-active, fade-enter-done, fade-exit, fade-exit-active, fade-exit-done, fade-appear, fade-appear-active, and fade-appear-done.

Note: Here, fade-enter-done and fade-appear-done both will be implemented. It will help you to understand and interpret the behavior for the time when the appearance is completed as well as when the routine entering is ensured. It is usually done with the help of the selectors such as .fade-enter-done:not(.fade-appear-done).

For instance, it is feasible for you to implement a grand form of entrance animation at the phase when the first element makes its presence in the Document Object Model (DOM) applying Animate.css. Apart from this, one can merely apply fade-enter-done for the cause of defining both types of cases.

It is worth mentioning that each singular classNames can be mentioned autonomously such as:

1
2
3
4
5
6
7
8
9
10
11
classNames={{
 appear: 'my-appear',
 appearActive: 'my-active-appear',
 appearDone: 'my-done-appear',
 enter: 'my-enter',
 enterActive: 'my-active-enter',
 enterDone: 'my-done-enter',
 exit: 'my-exit',
 exitActive: 'my-active-exit',
 exitDone: 'my-done-exit',
}}
javascript

In the case that you wish to set all these classes with the help of CSS Modules:

1
import styles from './styles.css';

Apart from that, one might wish to apply camelCase in one’s CSS file,. That way it would be easier to spread them in contrast of listing to each one after another:

1
2
3
classNames = { { ...styles } }
type: string | { appear?: string, appearActive?: string, appearDone?: string, enter?: string, enterActive?: string, enterDone?: string, exit?: string, exitActive?: string, exitDone?: string, }
default: ''

onEnter A <Transition> callback fired instantly after the enter or appear class is functional.

1
type: Function(node: HtmlElement, isAppearing: bool)

onEntering A <Transition> callback fired instantly after the enter-active or appear-active class is functional.

1
type: Function(node: HtmlElement, isAppearing: bool)

onEntered A <Transition> callback fired instantly after the enter or appear classes are detached and the done class is included to the Document Object Model (DOM) node.

1
type: Function(node: HtmlElement, isAppearing: bool)

onExit A <Transition> callback fired instantly after the exit class is functional.

1
type: Function(node: HtmlElement)

onExiting A <Transition> callback fired instantly after the exit-active is functional.

1
type: Function(node: HtmlElement)

onExited A <Transition> callback fired instantly after the exit classes are detached and the exit-done class is included to the Document Object Model (DOM) node.

1
type: Function(node: HtmlElement)

ReactJS Transition: CSS Class Removal

When we are talking about ReactJS transition, in terms of quick CSS class removal, the codes that are used are successful to a significant extent.

Speaking in terms of the general application, one can set to call setState({ flash: false }) which will be followed by the setState({ flash: 'up' }). It can help in the removal of the flash class from the Document Object Model element and include it again, which will hence enable the triggering of the JS CSS animation which is defined on that specific class (it only gives the desired results in the first phase).

In the ReactJS Transition: CSS Class removal process, there are certain results that are not as per the anticipation of the coder and the removal process only works when there is an introduction to certain timeouts. When the CSS class is added for the first time, it helps in the triggering of the animation. But all the subsequent calls made to componentWillReceiveProps are actually unsuccesful in triggering animation.

Stat.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import React, { Component } from 'react'
import { Link } from 'react-router'
import styles from './Stat.scss'

export default class Stat extends Component {
  constructor(props) {
    super(props)
    this.state = {
      flash: false,
    }
  }
  componentWillReceiveProps(nextProps) {
    if (nextProps.count !== this.props.count) {
      const flash = nextProps.count > this.props.count
        ? 'Up'
        : 'Down'
      this.setState({ flash: false }, () => {
        this.setState({ flash })
      })
    }
  }
  render() {
    const { count, name, href } = this.props
    const { flash } = this.state
    const flashClass = flash ? styles[`flash${flash}`] : ''
    return (
      <Link to={href} className="stat-link">
        <div className={`stat-number ${flashClass}`}>
          {count}
        </div>
        <div className="stat-label">{name}</div>
      </Link>
    )
  }
}
javascript

Stat.scss

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$highlight-up-color: green;
$highlight-down-color: red;

@keyframes highlight-up {
  0% {
    color: $highlight-up-color;
  }
  100% {
    color: default;
  }
}

@keyframes highlight-down {
  0% {
    color: $highlight-down-color;
  }
  100% {
    color: default;
  }
}

.flashUp {
  animation: highlight-up 2s;
}
.flashDown {
  animation: highlight-down 2s;
}
css

If, after the application of the codes, the problem persists, there is an option of using the codes that can enable a fix. But it is essential to realize that this trick only works in exception to the fact that animation is not in any way re-triggered if there is another one which is pending.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  componentWillReceiveProps(nextProps) {
    if (nextProps.count !== this.props.count) {
      const flash = nextProps.count > this.props.count
        ? 'Up'
        : 'Down'
      this.setState({ flash })
      if (__CLIENT__) {
        window.clearTimeout(this.timeout)
        this.timeout = window.setTimeout(() => {
          this.setState({ flash: false })
        }, 2000)
      }
    }
  }

  componentWillUnmount() {
    if (__CLIENT__) {
      clearTimeout(this.timeout)
    }
  }
javascript

Conclusion

The normal loophole that we find with ReactJS can be filled to a substantial extent with the above mentioned command. Yes, the exception is required to be kept in mind. The way ReactJS tends to update the Document Object Model (DOM) or an intrinsic restriction of the CSS transition animations. The application used to behave in such a manner because the way that ReactJS batches all the updates to the DOM with the RAF. It is a fact that ReactJS transition has some key utilities for the animations and that is why, in spite of this little limitation, it is a widely recommended application.

If, for the coder, the problem persists even after taking all the necessary precautions mentioned above, then it is advisable to apply forceUpdate for the successful removal of the class. Additionally, it is also suggestive to go for componentDidUpdate to get rid of the class there. It surely tends to work one way or the other.

References

The following resources have been referred to while writing this guide:

1