title: Problem with exit and enter animations using react-transition-group
body: <p>I'm new to React and I'm looking for some help.</p>
  
  <p>I'm trying to build a simple login page. The page gives users three options ('sign in with email', 'sign in with Google', or 'sign up') and displays a component based on the option chosen.</p>
  
  <p>I wanted to add a simple cross-fade as these components enter and exit the DOM so I turned to react-transition-group.</p>
  
  <p>The problem, however, is my components don't exit and enter properly. The old component appears to disappear instantly rather than fade out, two copies of the 'new' component are stacked on top of each other. One fades out and the other fades in. The old and new don't elegantly cross-fade into each other as I would like.</p>
  
  <p>Example:</p>
  
  <p><a href="https://i.stack.imgur.com/eTOCU.png" rel="nofollow noreferrer">Initial login page</a></p>
  
  <p><a href="https://i.stack.imgur.com/XoycR.png" rel="nofollow noreferrer">On click, two copies of the 'new' component appear, one fades in and the other fades out</a></p>
  
  <p><a href="https://i.stack.imgur.com/sw1aa.png" rel="nofollow noreferrer">transition completes and container now holds the new component as desired</a></p>
  
  <p>I've looked over <a href="https://reactcommunity.org/react-transition-group/" rel="nofollow noreferrer">the docs</a> for react-transition-group but I can't quite figure out what I'm doing wrong.</p>
  
  <p>Here's my main component:</p>
  
  <pre><code>class LoginPage extends React.Component {
      constructor(props) {
          super(props);
          this.state = {
              display: "loginInitial"
          }
      };
  
      handleEmailLogin = () =&gt; {
          this.setState(() =&gt; ({
              display: "emailLogin"
          }))     
      };
  
      handleGoogleLogin = () =&gt; {
          console.log("Logging in with google!")
          this.props.startGoogleLogin()
      };
  
      handleEmailSignUp= () =&gt; {
          this.setState(() =&gt; ({
              display: "emailSignUp"
          }))     
      };
  
      handleBackToStart = () =&gt; {
          this.setState(() =&gt; ({
              display: "loginInitial",
          }))     
      }
  
      displayBox = () =&gt; {
          if (this.state.display === "loginInitial") {
              return &lt;LoginPageInitial
                  handleEmailLogin={this.handleEmailLogin}
                  handleGoogleLogin={this.handleGoogleLogin}
                  handleEmailSignUp={this.handleEmailSignUp}
                  /&gt;
          } else if (this.state.display === "emailSignUp") {
              return &lt;LoginPageEmailSignUp
                  handleBackToStart={this.handleBackToStart}
                      /&gt;
          } else if (this.state.display === "emailLogin") {
              return &lt;LoginPageEmailLogin
                  handleBackToStart={this.handleBackToStart}
                      /&gt;
          }
      }
  
      render() {
          return (
              &lt;div className="box-layout"&gt;
              &lt;div className="box-layout__box"&gt;
                  &lt;h1 className="box-layout__title"&gt;My app&lt;/h1&gt;
                  &lt;p&gt;Subtitle goes here blah blah blah blah.&lt;/p&gt;
                      &lt;TransitionGroup&gt;
                              &lt;CSSTransition
                                  classNames="fade"
                                  timeout={600}
                                  key={this.state.display}
                              &gt;
                              {this.displayBox}
                              &lt;/CSSTransition&gt;
                      &lt;/TransitionGroup&gt;
              &lt;/div&gt;
          &lt;/div&gt;
          )
      };
  }
  
  const mapDispatchToProps = (dispatch) =&gt; ({
      startGoogleLogin: () =&gt; dispatch(startGoogleLogin())
  })
  
  export default connect(undefined, mapDispatchToProps)(LoginPage)
  </code></pre>
  
  <p>And here's the relevant CSS:</p>
  
  <pre><code>.box-layout {
      align-items: center;
      background: url('/images/bg.jpg');
      background-size: cover;
      display: flex;
      justify-content: center;
      height: 100vh;
      width: 100vw;
  }
  
  .box-layout__box {
      background: fade-out(white,.15);
      border-radius: 3px;
      text-align: center;
      width: 30rem;
      padding: $l-size $m-size
  }
  
  .box-layout__title {
      margin: 0 0  $m-size 0;
      line-height: 1;
  }
  
  // FADE
  // appear
  .fade-appear {
      opacity: 0;
      z-index: 1;
  }
  
  .fade-appear.fade-appear-active {
      opacity: 1;
      transition: opacity 600ms linear;
  }
  
  // enter
  .fade-enter {
      opacity: 0;
      z-index: 1;    
  }
  
  .fade-enter.fade-enter-active {
      opacity: 1;
      transition: opacity 600ms linear;    
  }
  
  // exit
  .fade-exit {
      opacity: 1;
  }
  
  .fade-exit.fade-exit-active {
      opacity: 0;
      transition: opacity 600ms linear;    
  }
  </code></pre>
  
  <p>I would be <strong><em>extremely</em></strong> appreciative if anyone can offer some advice. I've done a lot of googling but I can't find a solution to my problem.</p>
  
  <p>[<strong>EDIT:</strong> MOSTLY SOLVED - I managed to solve the bulk of my problem. It appears I needed to place my 'key' prop in my  component rather than  component. Two versions of the 'new' component no longer appear and the container doesn't stretch. It does appear, however, that the 'old' component still doesn't fade out as I expected. It looks a lot better than it did though. I welcome any further insight on what I was/am doing wrong or how I can improve my code.)</p>