4

I'd like to transition one element as it changes to another element.

I've got 3 examples:

What I want is more like the second one, which is a very slight variation of the first attempt that works.

Option 1:

/** @jsx React.DOM */

var ReactTransitionGroup = React.addons.TransitionGroup;

var TodoList = React.createClass({
  getInitialState: function() {
    return {items: ['hello', 'world', 'click', 'me']};
  },
  handleAdd: function() {
    var newItems =
      this.state.items.concat([prompt('Enter some text')]);
    this.setState({items: newItems});
  },
  handleRemove: function(i) {
    var newItems = this.state.items;
    newItems.splice(i, 1)
    this.setState({items: newItems});
    },

    render: function() {
        var items = this.state.items.map(function(item, i) {
            return (
                <div key={item} onClick={this.handleRemove.bind(this, i)}>
                    {item}
                </div>
            );
        }.bind(this));

        return (
            <div>
                <div><button onClick={this.handleAdd} /></div>
                <ReactTransitionGroup transitionName="example">
                    {items}
                </ReactTransitionGroup>
            </div>
        );
    }
});

var app = React.renderComponent(<TodoList />, document.body);

Option 2: JSX that doesn't work, but is closer to what I'd like to do (really, hide one view, and show another)

/** @jsx React.DOM */

var ReactTransitionGroup = React.addons.TransitionGroup;

var Test = React.createClass({
  getInitialState: function() {
    return {showOne:true}
  },
  onClick: function() {
    this.setState({showOne:! this.state.showOne});
  },
    render: function() {
      var result;
      if (this.state.showOne)
      {
        result = <div ref="a">One</div>
      }
      else 
      {
        result = <div ref="a">Two</div>
      }

        return (
            <div>
                <div><button onClick={this.onClick}>switch state</button></div>
                <ReactTransitionGroup transitionName="example">
                    {result}
                </ReactTransitionGroup>
            </div>
        );
    }
});

var app = React.renderComponent(<Test />, document.body);

Option 3: Uses hide/show to keep the 2 views around, but still doesn't work.

/** @jsx React.DOM */

var ReactTransitionGroup = React.addons.TransitionGroup;

var Test = React.createClass({
  getInitialState: function() {
    return {showOne:true}
  },
  onClick: function() {
    this.setState({showOne:! this.state.showOne});
  },
    render: function() {
      var result;
      var c1 = this.state.showOne ? "hide" : "show";
      var c2 = this.state.showOne ? "show" : "hide";


      return (
            <div>
                <div><button onClick={this.onClick}>switch state</button></div>
                <ReactTransitionGroup transitionName="example">
        <div className={c1}>One</div>
        <div className={c2}>Two</div>
                </ReactTransitionGroup>
            </div>
        );
    }
});

var app = React.renderComponent(<Test />, document.body);

So long story short - How can I make a transition execute on switching from one main "component" to another? I don't get why option 1 works, but option 2 doesn't!

2 Answers 2

15

React is just changing the content of the DOM because that's all that changed. Give the elements unique keys to make them animate.

  if (this.state.showOne)
  {
    result = <div key="one">One</div>
  }
  else 
  {
    result = <div key="two">Two</div>
  }

JSFiddle

Sign up to request clarification or add additional context in comments.

1 Comment

binary muse u da shiiiiiet
1

I used Michelle Treys answer to solve a similar problem using React-Router (1.0.1). Its not clear from the api that the key is needed. I was following React-routers suggestion to render a routes children in a parent as follows:

render() {
    return (
        <div id='app-wrapper'>
          <ReactTransitionGroup component='div' className='transition-wrapper'>
            {this.props.children}
          </ReactTransitionGroup>
        </div>
    );
  }

However the componentWillEnter only triggered on page load. Following Michelle's solution, I cloned a the children as per the react-router updates and added a key as follows:

render() {

    const { location } = this.props;

    return (
        <div id='app-wrapper'>
          <ReactTransitionGroup component='div' className='transition-wrapper'>
            {React.cloneElement(this.props.children, {
              key: location.pathname,
            })}
          </ReactTransitionGroup>
        </div>
    );
  }

Thanks for the fix. Cheers

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.