Skip to content

Commit

Permalink
[fixed] respect closeTimeoutMS during unmount
Browse files Browse the repository at this point in the history
Fixes issue reactjs#17: "When the modal is unmounted, it will abruptly close,
not waiting for any animations to finish."

The bug was caused by the Modal component unmounting the portal
immediately in `componentWillUnmount` regardless of whether the portal
is currently closing or would animate to close.

Now when a Modal has a non-zero closeTimeoutMS, the Modal inspects the
portal state before closing.  If the portal is open or closing, but not
closed, it waits to unmount the portal.  If the portal is open and not
already closing, the Modal calls closeWithTimeout() to trigger the
close.
  • Loading branch information
Martin Hunt committed Oct 13, 2016
1 parent 11c1fd6 commit 22676ea
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 3 deletions.
18 changes: 18 additions & 0 deletions lib/components/Modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,24 @@ var Modal = React.createClass({
},

componentWillUnmount: function() {
var state = this.portal.state;
var now = Date.now();
var closesAt = state.isOpen && this.props.closeTimeoutMS
&& (state.closesAt
|| now + this.props.closeTimeoutMS);

if (closesAt) {
if (!state.beforeClose) {
this.portal.closeWithTimeout();
}

setTimeout(this.removePortal, closesAt - now);
} else {
this.removePortal();
}
},

removePortal: function() {
ReactDOM.unmountComponentAtNode(this.node);
document.body.removeChild(this.node);
elementClass(document.body).remove('ReactModal__Body--open');
Expand Down
8 changes: 5 additions & 3 deletions lib/components/ModalPortal.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,9 @@ var ModalPortal = module.exports = React.createClass({
},

closeWithTimeout: function() {
this.setState({beforeClose: true}, function() {
this.closeTimer = setTimeout(this.closeWithoutTimeout, this.props.closeTimeoutMS);
var closesAt = Date.now() + this.props.closeTimeoutMS;
this.setState({beforeClose: true, closesAt: closesAt}, function() {
this.closeTimer = setTimeout(this.closeWithoutTimeout, this.state.closesAt - Date.now());
}.bind(this));
},

Expand All @@ -116,6 +117,7 @@ var ModalPortal = module.exports = React.createClass({
beforeClose: false,
isOpen: false,
afterOpen: false,
closesAt: null
}, this.afterClose);
},

Expand Down Expand Up @@ -166,7 +168,7 @@ var ModalPortal = module.exports = React.createClass({
},

shouldBeClosed: function() {
return !this.props.isOpen && !this.state.beforeClose;
return !this.state.isOpen && !this.state.beforeClose;
},

contentHasFocus: function() {
Expand Down

0 comments on commit 22676ea

Please sign in to comment.