@@ -12,6 +12,9 @@ import ReactCSSTransitionGroupChild from 'react/lib/ReactCSSTransitionGroupChild
12
12
13
13
const reactCSSTransitionGroupChild = React . createFactory ( ReactCSSTransitionGroupChild ) ;
14
14
15
+ const TICK = 17 ;
16
+
17
+
15
18
function createTransitionTimeoutPropValidator ( transitionType ) {
16
19
const timeoutPropName = 'transition' + transitionType + 'Timeout' ;
17
20
const enabledPropName = 'transition' + transitionType ;
@@ -57,8 +60,9 @@ export default class ReactCSSTransitionReplace extends React.Component {
57
60
} ;
58
61
59
62
state = {
60
- currentChild : React . Children . only ( this . props . children ) ,
61
- nextChild : null
63
+ currentChild : this . props . children ? React . Children . only ( this . props . children ) : null ,
64
+ nextChild : null ,
65
+ height : null
62
66
} ;
63
67
64
68
componentDidMount ( ) {
@@ -67,8 +71,15 @@ export default class ReactCSSTransitionReplace extends React.Component {
67
71
}
68
72
}
69
73
74
+ componentWillUnmount ( ) {
75
+ if ( this . timeout ) {
76
+ clearTimeout ( this . timeout ) ;
77
+ }
78
+ }
79
+
70
80
componentWillReceiveProps ( nextProps ) {
71
- const nextChild = nextProps . children ? React . Children . only ( nextProps . children ) : null ;
81
+ // Setting false indicates that the child has changed, but it is a removal so there is no next child.
82
+ const nextChild = nextProps . children ? React . Children . only ( nextProps . children ) : false ;
72
83
const currentChild = this . state . currentChild ;
73
84
74
85
if ( currentChild && nextChild && nextChild . key === currentChild . key ) {
@@ -78,38 +89,30 @@ export default class ReactCSSTransitionReplace extends React.Component {
78
89
} ) ;
79
90
}
80
91
81
- // Set the next child to start the transition,
82
- // also set the current and next height to trigger its transition.
92
+ // Set the next child to start the transition, and set the current height.
83
93
this . setState ( {
84
94
nextChild,
85
- height : ReactDOM . findDOMNode ( this . refs . curr ) . offsetHeight
86
- } , ( ) => this . setState ( {
87
- height : ReactDOM . findDOMNode ( this . refs . next ) . offsetHeight
88
- } ) ) ;
95
+ height : this . state . currentChild ? ReactDOM . findDOMNode ( this . refs . curr ) . offsetHeight : 0
96
+ } ) ;
97
+
98
+ // Enqueue setting the next height to trigger the height transition.
99
+ this . timeout = setTimeout ( ( ) => {
100
+ this . setState ( { height : this . state . nextChild ? ReactDOM . findDOMNode ( this . refs . next ) . offsetHeight : 0 } ) ;
101
+ this . timeout = null ;
102
+ } , TICK ) ;
89
103
}
90
104
91
105
componentDidUpdate ( ) {
92
- if ( this . state . nextChild && ! this . isTransitioning ) {
93
- this . enterNext ( ) ;
94
- this . leaveCurrent ( ) ;
106
+ if ( ! this . isTransitioning ) {
107
+ if ( this . state . nextChild ) {
108
+ this . enterNext ( ) ;
109
+ }
110
+ if ( this . state . currentChild && ( this . state . nextChild || this . state . nextChild === false ) ) {
111
+ this . leaveCurrent ( ) ;
112
+ }
95
113
}
96
114
}
97
115
98
- _wrapChild ( child , moreProps ) {
99
- // We need to provide this childFactory so that
100
- // ReactCSSTransitionReplaceChild can receive updates to name,
101
- // enter, and leave while it is leaving.
102
- return reactCSSTransitionGroupChild ( objectAssign ( {
103
- name : this . props . transitionName ,
104
- appear : this . props . transitionAppear ,
105
- enter : this . props . transitionEnter ,
106
- leave : this . props . transitionLeave ,
107
- appearTimeout : this . props . transitionAppearTimeout ,
108
- enterTimeout : this . props . transitionEnterTimeout ,
109
- leaveTimeout : this . props . transitionLeaveTimeout
110
- } , moreProps ) , child ) ;
111
- }
112
-
113
116
appearCurrent ( ) {
114
117
this . refs . curr . componentWillAppear ( this . _handleDoneAppearing ) ;
115
118
this . isTransitioning = true ;
@@ -135,18 +138,39 @@ export default class ReactCSSTransitionReplace extends React.Component {
135
138
136
139
leaveCurrent ( ) {
137
140
this . refs . curr . componentWillLeave ( this . _handleDoneLeaving ) ;
141
+ this . isTransitioning = true ;
138
142
}
139
143
140
- // When the leave transition timeOut expires the animation classes are removed, so the
144
+ // When the leave transition time-out expires the animation classes are removed, so the
141
145
// element must be removed from the DOM if the enter transition is still in progress.
142
146
_handleDoneLeaving = ( ) => {
143
147
if ( this . isTransitioning ) {
144
- this . setState ( {
145
- currentChild : null
146
- } ) ;
148
+ const state = { currentChild : null } ;
149
+
150
+ if ( ! this . state . nextChild ) {
151
+ this . isTransitioning = false ;
152
+ state . height = null ;
153
+ }
154
+
155
+ this . setState ( state ) ;
147
156
}
148
157
} ;
149
158
159
+ _wrapChild ( child , moreProps ) {
160
+ // We need to provide this childFactory so that
161
+ // ReactCSSTransitionReplaceChild can receive updates to name,
162
+ // enter, and leave while it is leaving.
163
+ return reactCSSTransitionGroupChild ( objectAssign ( {
164
+ name : this . props . transitionName ,
165
+ appear : this . props . transitionAppear ,
166
+ enter : this . props . transitionEnter ,
167
+ leave : this . props . transitionLeave ,
168
+ appearTimeout : this . props . transitionAppearTimeout ,
169
+ enterTimeout : this . props . transitionEnterTimeout ,
170
+ leaveTimeout : this . props . transitionLeaveTimeout
171
+ } , moreProps ) , child ) ;
172
+ }
173
+
150
174
render ( ) {
151
175
const { currentChild, nextChild, height } = this . state ;
152
176
const childrenToRender = [ ] ;
@@ -159,20 +183,20 @@ export default class ReactCSSTransitionReplace extends React.Component {
159
183
} ) ) ;
160
184
}
161
185
162
- if ( nextChild ) {
163
- objectAssign ( containerProps , {
164
- className : `${ containerProps . className || '' } ${ containerProps . transitionName } -height` ,
165
- style : objectAssign ( { } , containerProps . style , {
166
- position : 'relative' ,
167
- display : 'block' ,
168
- height
169
- } )
186
+ if ( height !== null ) {
187
+ containerProps . className = `${ containerProps . className || '' } ${ containerProps . transitionName } -height` ;
188
+ containerProps . style = objectAssign ( { } , containerProps . style , {
189
+ position : 'relative' ,
190
+ display : 'block' ,
191
+ height
170
192
} ) ;
171
193
172
194
if ( overflowHidden ) {
173
195
containerProps . style . overflow = 'hidden' ;
174
196
}
197
+ }
175
198
199
+ if ( nextChild ) {
176
200
childrenToRender . push (
177
201
React . createElement ( 'span' ,
178
202
{
0 commit comments