diff --git a/src/addons/transitions/ReactCSSTransitionGroup.js b/src/addons/transitions/ReactCSSTransitionGroup.js index 2e4190c729..dd481eef6b 100644 --- a/src/addons/transitions/ReactCSSTransitionGroup.js +++ b/src/addons/transitions/ReactCSSTransitionGroup.js @@ -28,12 +28,14 @@ var ReactCSSTransitionGroup = React.createClass({ propTypes: { transitionName: React.PropTypes.string.isRequired, + transitionAppear: React.PropTypes.bool, transitionEnter: React.PropTypes.bool, transitionLeave: React.PropTypes.bool }, getDefaultProps: function() { return { + transitionAppear: false, transitionEnter: true, transitionLeave: true }; @@ -46,6 +48,7 @@ var ReactCSSTransitionGroup = React.createClass({ return ReactCSSTransitionGroupChild( { name: this.props.transitionName, + appear: this.props.transitionAppear, enter: this.props.transitionEnter, leave: this.props.transitionLeave }, diff --git a/src/addons/transitions/ReactCSSTransitionGroupChild.js b/src/addons/transitions/ReactCSSTransitionGroupChild.js index 3feb6c78dd..6bdcf90e16 100644 --- a/src/addons/transitions/ReactCSSTransitionGroupChild.js +++ b/src/addons/transitions/ReactCSSTransitionGroupChild.js @@ -107,6 +107,14 @@ var ReactCSSTransitionGroupChild = React.createClass({ } }, + componentWillAppear: function(done) { + if (this.props.appear) { + this.transition('appear', done); + } else { + done(); + } + }, + componentWillEnter: function(done) { if (this.props.enter) { this.transition('enter', done); diff --git a/src/addons/transitions/ReactTransitionGroup.js b/src/addons/transitions/ReactTransitionGroup.js index ce967cff4c..80296e4e48 100644 --- a/src/addons/transitions/ReactTransitionGroup.js +++ b/src/addons/transitions/ReactTransitionGroup.js @@ -39,6 +39,21 @@ var ReactTransitionGroup = React.createClass({ }; }, + componentWillMount: function() { + this.currentlyTransitioningKeys = {}; + this.keysToEnter = []; + this.keysToLeave = []; + }, + + componentDidMount: function() { + var initialChildMapping = this.state.children; + for (var key in initialChildMapping) { + if (initialChildMapping[key]) { + this.performAppear(key); + } + } + }, + componentWillReceiveProps: function(nextProps) { var nextChildMapping = ReactTransitionChildMapping.getChildMapping( nextProps.children @@ -73,12 +88,6 @@ var ReactTransitionGroup = React.createClass({ // If we want to someday check for reordering, we could do it here. }, - componentWillMount: function() { - this.currentlyTransitioningKeys = {}; - this.keysToEnter = []; - this.keysToLeave = []; - }, - componentDidUpdate: function() { var keysToEnter = this.keysToEnter; this.keysToEnter = []; @@ -89,6 +98,38 @@ var ReactTransitionGroup = React.createClass({ keysToLeave.forEach(this.performLeave); }, + performAppear: function(key) { + this.currentlyTransitioningKeys[key] = true; + + var component = this.refs[key]; + + if (component.componentWillAppear) { + component.componentWillAppear( + this._handleDoneAppearing.bind(this, key) + ); + } else { + this._handleDoneAppearing(key); + } + }, + + _handleDoneAppearing: function(key) { + var component = this.refs[key]; + if (component.componentDidAppear) { + component.componentDidAppear(); + } + + delete this.currentlyTransitioningKeys[key]; + + var currentChildMapping = ReactTransitionChildMapping.getChildMapping( + this.props.children + ); + + if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) { + // This was removed before it had fully appeared. Remove it. + this.performLeave(key); + } + }, + performEnter: function(key) { this.currentlyTransitioningKeys[key] = true; diff --git a/src/addons/transitions/__tests__/ReactTransitionGroup-test.js b/src/addons/transitions/__tests__/ReactTransitionGroup-test.js index feddef8538..1a4b23fc25 100644 --- a/src/addons/transitions/__tests__/ReactTransitionGroup-test.js +++ b/src/addons/transitions/__tests__/ReactTransitionGroup-test.js @@ -36,6 +36,13 @@ describe('ReactTransitionGroup', function() { componentDidMount: function() { log.push('didMount'); }, + componentWillAppear: function(cb) { + log.push('willAppear'); + cb(); + }, + componentDidAppear: function() { + log.push('didAppear'); + }, componentWillEnter: function(cb) { log.push('willEnter'); cb(); @@ -72,15 +79,15 @@ describe('ReactTransitionGroup', function() { }); var instance = React.render(, container); - expect(log).toEqual(['didMount']); + expect(log).toEqual(['didMount', 'willAppear', 'didAppear']); + log = []; instance.setState({count: 2}, function() { - expect(log).toEqual(['didMount', 'didMount', 'willEnter', 'didEnter']); + expect(log).toEqual(['didMount', 'willEnter', 'didEnter']); + + log = []; instance.setState({count: 1}, function() { - expect(log).toEqual([ - "didMount", "didMount", "willEnter", "didEnter", - "willLeave", "didLeave", "willUnmount" - ]); + expect(log).toEqual(['willLeave', 'didLeave', 'willUnmount']); }); }); });