Skip to content

Commit 22676ea

Browse files
author
Martin Hunt
committed
[fixed] respect closeTimeoutMS during unmount
Fixes issue #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.
1 parent 11c1fd6 commit 22676ea

File tree

2 files changed

+23
-3
lines changed

2 files changed

+23
-3
lines changed

lib/components/Modal.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,24 @@ var Modal = React.createClass({
6262
},
6363

6464
componentWillUnmount: function() {
65+
var state = this.portal.state;
66+
var now = Date.now();
67+
var closesAt = state.isOpen && this.props.closeTimeoutMS
68+
&& (state.closesAt
69+
|| now + this.props.closeTimeoutMS);
70+
71+
if (closesAt) {
72+
if (!state.beforeClose) {
73+
this.portal.closeWithTimeout();
74+
}
75+
76+
setTimeout(this.removePortal, closesAt - now);
77+
} else {
78+
this.removePortal();
79+
}
80+
},
81+
82+
removePortal: function() {
6583
ReactDOM.unmountComponentAtNode(this.node);
6684
document.body.removeChild(this.node);
6785
elementClass(document.body).remove('ReactModal__Body--open');

lib/components/ModalPortal.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,9 @@ var ModalPortal = module.exports = React.createClass({
106106
},
107107

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

@@ -116,6 +117,7 @@ var ModalPortal = module.exports = React.createClass({
116117
beforeClose: false,
117118
isOpen: false,
118119
afterOpen: false,
120+
closesAt: null
119121
}, this.afterClose);
120122
},
121123

@@ -166,7 +168,7 @@ var ModalPortal = module.exports = React.createClass({
166168
},
167169

168170
shouldBeClosed: function() {
169-
return !this.props.isOpen && !this.state.beforeClose;
171+
return !this.state.isOpen && !this.state.beforeClose;
170172
},
171173

172174
contentHasFocus: function() {

0 commit comments

Comments
 (0)