0

I seem to lack fundamental understanding of how React Transition Group works. In this simple example, I expect the component to fade in on each update. It does not. Why is that the case? If I toggle the in prop for , then it does work.

import React from 'react';
import ReactDOM from 'react-dom';
import { Container, Button, Alert } from 'react-bootstrap';
import { CSSTransition } from 'react-transition-group';

import './styles.css';
class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      rerender: false,
    };
    this.toggle = this.toggle.bind(this);
  }
  toggle() {
    this.setState((state) => ({
      rerender: !state.rerender,
    }));
  }
  componentDidMount() {
    console.log('Mounted');
  }
  componentDidUpdate() {
    console.log('Updated');
  }
  render() {
    return (
      <div>
        <Button onClick={this.toggle}>Click</Button>
         <CSSTransition
          classNames="fade"
          in = {true}
          timeout={1000}
        >
           {this.state.rerender ?  <p> Render On </p> : <p>Render Off</p>}
        </CSSTransition>
      </div>
    );
  }
}
ReactDOM.render(
  <Example />,
  document.getElementById('root')
);

Here is the CSS

.fade-enter {
  opacity: 1;
}
.fade-enter-active {
  opacity: 0;
  transition-property: opacity;
  transition-duration: 1000ms;
}
.fade-enter-done {
  opacity: 0;
}

From what I route read, I thought that leaving the "in" prop for as always true, will always apply the enter-* CSS classes on each component update. As you can see though, when I press the button, hence updating the component. No animation takes place: https://codesandbox.io/s/beautiful-brahmagupta-6nmze?file=/index.js On the other hand, if I toggle the in prop with true and false, then the entering classes will be applied. Try it in the code sandbox and see for yourself.

...
<CSSTransition
          classNames="fade"
          in = {this.state.rerender}
          timeout={1000}
        >
...

1 Answers1

2

As far as I know, React Transition Groups works only in transition stages so in prop should be

  • false to true
  • true to false

you can see that clearly in the source code

_proto.componentDidUpdate = function componentDidUpdate(prevProps) {
  var nextStatus = null;

  if (prevProps !== this.props) {
    var status = this.state.status;

    if (this.props.in) {
      if (status !== ENTERING && status !== ENTERED) {
        nextStatus = ENTERING;
      }
    } else {
      if (status === ENTERING || status === ENTERED) {
        nextStatus = EXITING;
      }
    }
  }

  this.updateStatus(false, nextStatus);
};

_proto.updateStatus = function updateStatus(mounting, nextStatus) {
  if (mounting === void 0) {
    mounting = false;
  }

  if (nextStatus !== null) {
    // nextStatus will always be ENTERING or EXITING.
    this.cancelNextCallback();

    if (nextStatus === ENTERING) {
      this.performEnter(mounting);
    } else {
      this.performExit();
    }
  } else if (this.props.unmountOnExit && this.state.status === EXITED) {
    this.setState({
      status: UNMOUNTED
    });
  }
};

So if props not changed nothing will happened.

In your case, you are trying to apply enter-* classes only: you can let in = {this.state.rerender} and provide enter-* classes in css file without exit-*

Also you can use another library to animate component when mounting like: React-animations