2

I am trying to get a transition between components entering and leaving when the button is clicked to toggle between state

I have also tried putting <UserDetails /> and <UserEdit /> as seperate components but have the same result in that no animation is triggered.

https://www.webpackbin.com/bins/-KjIPcMeQF3iriHRqTBW

Hello.js

import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup'
import './styles.css'
export default class Hello extends React.Component {
constructor() {
super()

this.state = { showEdit: false }
this.handleEdit = this.handleEdit.bind(this)
}

handleEdit() { this.setState({ showEdit: !this.state.showEdit }) } 

render() {

 const UserDetails = () => (
 <div className="componenta" key="1">UserDetails</div>
 )
 const UserEdit = () => (
 <div className="componentb" key="2">UserEdit</div>
 )

return(
<div >
    <CSSTransitionGroup 
      transitionName="example"
      transitionEnterTimeout={10}
      transitionLeaveTimeout={600}>
    {this.state.showEdit ? <UserDetails /> : <UserEdit />}
    </CSSTransitionGroup>
    <button onClick={this.handleEdit}>Toggle</button>
</div>
)
}
}

styles.css

.thing-enter {
 opacity: 0.01;
 transition: opacity 1s ease-in;
}

.thing-enter.thing-enter-active {
  opacity: 1;
}

 .thing-leave {
  opacity: 1;
  transition: opacity 1s ease-in;
 }

 .thing-leave.thing-leave-active {
  opacity: 0.01;
 }
tom harrison
  • 3,273
  • 11
  • 42
  • 71

2 Answers2

1

You have your key attribute set to the wrong item - the <div> is not the direct descendant of CSSTransitionGroup (because your wrapped it into a component by defining it as a function), so it doesn't know which items were added or removed. You have to set your keys to UserDetails and UserEdit, so CSSTransitionGroup can properly determine changes in it's children.

Here is your render method that works:

render() {

    const UserDetails = () => (
      <div className="componenta">UserDetails</div>
    )
    const UserEdit = () => (
      <div className="componentb">UserEdit</div>
    )
    return(
    <div >
        <CSSTransitionGroup 
          transitionName="example"
          transitionEnterTimeout={10}
          transitionLeaveTimeout={600}>
        {this.state.showEdit ? <UserDetails key="1" /> : <UserEdit key="2" />}
        </CSSTransitionGroup>
        <button onClick={this.handleEdit}>Toggle</button>
    </div>
    )
  }

An alternative would be to store UserDetails and UserEdit into variables and then render them as such. That will allow you to leave the key attributes where they are now, instead of moving them.

Gregor Menih
  • 5,036
  • 14
  • 44
  • 66
  • thanks for the explanation makes more sense to me now, How can I prevent both components from displaying at the same time when toggling between them? Currently they appear beneath each other when transitioning but I would like it to fade in/out in the same position on top of each other – tom harrison May 04 '17 at 14:04
  • @tomharrison I would solve that with CSS. Either set a delay on the `.thing-enter` transition or set absolute positioning to the elements, so they can be drawn over each other. – Gregor Menih May 04 '17 at 14:33
  • perfect! I have positioned absolutely as I couldn't get delay working as intended the webpack.bin has been updated with working example – tom harrison May 04 '17 at 15:04
0

Here is a working example using display:none to hide the unmounting component

enter link description here

tom harrison
  • 3,273
  • 11
  • 42
  • 71