Merge pull request #2549 from ashtuchkin/fix-transitiongroup-multiremove

Fix ReactTransitionGroup behavior when removing several children at once
This commit is contained in:
Ben Alpert
2015-04-01 14:33:42 -07:00
2 changed files with 70 additions and 3 deletions
@@ -89,6 +89,8 @@ var ReactTransitionGroup = React.createClass({
},
componentDidUpdate: function() {
this.updatedChildren = null;
var keysToEnter = this.keysToEnter;
this.keysToEnter = [];
keysToEnter.forEach(this.performEnter);
@@ -193,9 +195,13 @@ var ReactTransitionGroup = React.createClass({
// This entered again before it fully left. Add it again.
this.performEnter(key);
} else {
var newChildren = assign({}, this.state.children);
delete newChildren[key];
this.setState({children: newChildren});
// As this.state.children will not be updated until next render, we keep
// this.updatedChildren state to avoid losing all but the last removal.
// It's cleaned after this.state is updated, in componentDidUpdate.
if (!this.updatedChildren)
this.updatedChildren = assign({}, this.state.children);
delete this.updatedChildren[key];
this.setState({children: this.updatedChildren});
}
},
@@ -208,4 +208,65 @@ describe('ReactTransitionGroup', function() {
'didMount', 'didMount', 'willEnter', 'didEnter'
]);
});
it('should handle entering/leaving several elements at once', function() {
var log = [];
var cb;
var Child = React.createClass({
componentDidMount: function() {
log.push('didMount'+this.props.id);
},
componentWillEnter: function(cb) {
log.push('willEnter'+this.props.id);
cb();
},
componentDidEnter: function() {
log.push('didEnter'+this.props.id);
},
componentWillLeave: function(cb) {
log.push('willLeave'+this.props.id);
cb();
},
componentDidLeave: function() {
log.push('didLeave'+this.props.id);
},
componentWillUnmount: function() {
log.push('willUnmount'+this.props.id);
},
render: function() {
return <span />;
}
});
var Component = React.createClass({
getInitialState: function() {
return {count: 1};
},
render: function() {
var children = [];
for (var i = 0; i < this.state.count; i++) {
children.push(<Child key={i} id={i} />);
}
return <ReactTransitionGroup>{children}</ReactTransitionGroup>;
}
});
var instance = React.render(<Component />, container);
expect(log).toEqual(['didMount0']);
log = [];
instance.setState({count: 3});
expect(log).toEqual([
'didMount1', 'didMount2', 'willEnter1', 'didEnter1',
'willEnter2', 'didEnter2'
]);
log = [];
instance.setState({count: 0});
expect(log).toEqual([
'willLeave0', 'didLeave0', 'willLeave1', 'didLeave1',
'willLeave2', 'didLeave2', 'willUnmount0', 'willUnmount1', 'willUnmount2'
]);
});
});