9
9
"use strict" ;
10
10
11
11
var React = require ( 'react' )
12
+ , startsWith = require ( '../util/filter' ) . startsWith
12
13
, cloneWithProps = require ( '../util/transferProps' ) . cloneWithProps
13
14
, transferPropsTo = require ( '../util/transferProps' ) . mergeIntoProps
14
15
, $ = require ( '../util/dom' )
15
16
, _ = require ( '../util/_' ) ;
16
17
18
+
19
+
17
20
module . exports = React . createClass ( {
18
21
19
22
displayName : 'ReplaceTransitionGroup' ,
@@ -31,95 +34,94 @@ module.exports = React.createClass({
31
34
component : React . DOM . span ,
32
35
childFactory : function ( a ) { return a } ,
33
36
34
- onAnimating : function ( ) { } ,
35
- onAnimate : function ( ) { }
37
+ onAnimating : _ . noop ,
38
+ onAnimate : _ . noop
36
39
} ;
37
40
} ,
38
41
39
42
getInitialState : function ( ) {
40
43
return {
41
- children : React . Children . map ( this . props . children , function ( c ) { return c } )
44
+ children : _ . splat ( this . props . children )
42
45
} ;
43
46
} ,
44
47
45
48
componentWillReceiveProps : function ( nextProps ) {
46
- var nextChildMapping = React . Children . map ( nextProps . children , function ( c ) { return c } )
47
- , prevChildMapping = this . state . children
48
- , key , hasOther , isNext ;
49
-
50
- //console.log(prevChildMapping, nextChildMapping)
51
- this . setState ( {
52
- children : _ . merge ( prevChildMapping , nextChildMapping )
53
- } ) ;
54
-
55
- for ( key in nextChildMapping ) if ( _ . has ( nextChildMapping , key ) )
56
- {
57
- hasOther = prevChildMapping && _ . has ( prevChildMapping , key )
58
- isNext = ! hasOther && ! this . currentlyTransitioningKeys [ key ] ;
59
-
60
- if ( isNext ) {
61
- this . next = key
62
- break
63
- }
49
+ var nextChild = getChild ( nextProps . children )
50
+ , stack = this . state . children . slice ( )
51
+ , next = stack [ 1 ]
52
+ , last = stack [ 0 ] ;
53
+
54
+ var isLastChild = last && key ( last ) === key ( nextChild )
55
+ , isNextChild = next && key ( next ) === key ( nextChild ) ;
56
+
57
+ //no children
58
+ if ( ! last ) {
59
+ stack . push ( nextChild )
60
+ this . entering = nextChild
64
61
}
65
-
66
- for ( key in prevChildMapping ) if ( _ . has ( prevChildMapping , key ) )
67
- {
68
- hasOther = nextChildMapping && _ . has ( nextChildMapping , key )
69
- isNext = ! hasOther && ! this . currentlyTransitioningKeys [ key ] ;
70
-
71
- if ( isNext ) {
72
- this . current = key
73
- break
74
- }
62
+ else if ( last && ! next && ! isLastChild ) {
63
+ //new child
64
+ stack . push ( nextChild )
65
+ this . leaving = last
66
+ this . entering = nextChild
75
67
}
68
+ else if ( last && next && ! isLastChild && ! isNextChild ) {
69
+ // the child is not the current one, exit the current one, add the new one
70
+ // - shift the stack down
71
+ stack . shift ( )
72
+ stack . push ( nextChild )
73
+ this . leaving = next
74
+ this . entering = nextChild
75
+ }
76
+ //new child that just needs to be re-rendered
77
+ else if ( isLastChild ) stack . splice ( 0 , 1 , nextChild )
78
+ else if ( isNextChild ) stack . splice ( 1 , 1 , nextChild )
79
+
80
+ if ( this . state . children [ 0 ] !== stack [ 0 ] || this . state . children [ 1 ] !== stack [ 1 ] )
81
+ this . setState ( { children : stack } ) ;
76
82
} ,
77
83
78
84
componentWillMount : function ( ) {
79
- this . currentlyTransitioningKeys = { } ;
80
- this . current = null ;
81
- this . next = null ;
85
+ this . animatingKeys = { } ;
86
+ this . leaving = null ;
87
+ this . entering = null ;
82
88
} ,
83
89
84
90
componentDidUpdate : function ( ) {
85
- var current = this . current
86
- , next = this . next
87
- , first = this . refs [ current || next ]
88
- , node = this . getDOMNode ( )
89
- , el = first && first . getDOMNode ( )
90
- , ht , wt ;
91
-
92
- if ( el ) {
93
- ht = $ . height ( el ) + 'px'
94
- wt = $ . width ( el ) + 'px'
91
+ var entering = this . entering
92
+ , leaving = this . leaving
93
+ , first = this . refs [ key ( entering ) || key ( leaving ) ]
94
+ , node = this . getDOMNode ( )
95
+ , el = first && first . getDOMNode ( ) ;
95
96
97
+ if ( el )
96
98
$ . css ( node , {
97
99
overflow : 'hidden' ,
98
- height : ht ,
99
- width : wt
100
+ height : $ . height ( el ) + 'px' ,
101
+ width : $ . width ( el ) + 'px'
100
102
} )
101
- }
102
-
103
+
103
104
this . props . onAnimating ( ) ;
104
105
105
- this . next = null ;
106
- this . current = null ;
106
+ this . entering = null ;
107
+ this . leaving = null ;
107
108
108
- if ( next ) this . performEnter ( next )
109
- if ( current ) this . performLeave ( current )
109
+ if ( entering ) this . performEnter ( key ( entering ) )
110
+ if ( leaving ) this . performLeave ( key ( leaving ) )
110
111
} ,
111
112
112
113
performEnter : function ( key ) {
113
- this . currentlyTransitioningKeys [ key ] = true ;
114
-
115
114
var component = this . refs [ key ] ;
116
115
116
+ if ( ! component ) return
117
+
118
+ this . animatingKeys [ key ] = true ;
119
+
117
120
if ( component . componentWillEnter )
118
121
component . componentWillEnter (
119
122
this . _handleDoneEntering . bind ( this , key ) ) ;
120
123
else
121
124
this . _handleDoneEntering ( key ) ;
122
-
123
125
} ,
124
126
125
127
_tryFinish : function ( ) {
@@ -128,84 +130,72 @@ module.exports = React.createClass({
128
130
if ( this . isTransitioning ( ) )
129
131
return
130
132
131
- $ . css ( node , {
132
- overflow : 'visible' ,
133
- height : '' ,
134
- width : ''
135
- } )
133
+ $ . css ( node , { overflow : 'visible' , height : '' , width : '' } )
136
134
137
135
this . props . onAnimate ( )
138
136
} ,
139
137
140
- _handleDoneEntering : function ( key ) {
141
- var component = this . refs [ key ] ;
138
+ _handleDoneEntering : function ( enterkey ) {
139
+ var component = this . refs [ enterkey ] ;
142
140
143
- if ( component . componentDidEnter )
141
+ if ( component && component . componentDidEnter )
144
142
component . componentDidEnter ( ) ;
145
143
146
- delete this . currentlyTransitioningKeys [ key ] ;
147
-
148
- var currentChildMapping = React . Children . map ( this . props . children , function ( c ) { return c } )
144
+ delete this . animatingKeys [ enterkey ] ;
149
145
150
- if ( ! currentChildMapping || ! _ . has ( currentChildMapping , key ) )
151
- this . performLeave ( key ) ; // This was removed before it had fully entered. Remove it.
146
+ if ( key ( this . props . children ) !== enterkey )
147
+ this . performLeave ( enterkey ) ; // This was removed before it had fully entered. Remove it.
152
148
153
149
this . _tryFinish ( )
154
150
} ,
155
151
156
152
isTransitioning : function ( ) {
157
- return Object . keys ( this . currentlyTransitioningKeys ) . length !== 0
153
+ return Object . keys ( this . animatingKeys ) . length !== 0
158
154
} ,
159
155
160
156
performLeave : function ( key ) {
161
157
var component = this . refs [ key ] ;
162
158
163
- this . currentlyTransitioningKeys [ key ] = true ;
159
+ if ( ! component ) return
160
+
161
+ this . animatingKeys [ key ] = true ;
164
162
165
163
if ( component . componentWillLeave )
166
164
component . componentWillLeave ( this . _handleDoneLeaving . bind ( this , key ) ) ;
167
165
else
168
166
this . _handleDoneLeaving ( key ) ;
169
-
170
167
} ,
171
168
172
- _handleDoneLeaving : function ( key ) {
173
- var component = this . refs [ key ] ;
169
+ _handleDoneLeaving : function ( leavekey ) {
170
+ var component = this . refs [ leavekey ] ;
174
171
175
- if ( component . componentDidLeave )
172
+ if ( component && component . componentDidLeave )
176
173
component . componentDidLeave ( ) ;
177
174
178
- delete this . currentlyTransitioningKeys [ key ] ;
179
-
180
- var currentChildMapping = React . Children . map ( this . props . children , function ( c ) { return c } )
175
+ delete this . animatingKeys [ leavekey ] ;
181
176
182
- if ( currentChildMapping && currentChildMapping . hasOwnProperty ( key ) )
183
- this . performEnter ( key ) ; // This entered again before it fully left. Add it again.
177
+ if ( key ( this . props . children ) === leavekey )
178
+ this . performEnter ( leavekey ) ; // This entered again before it fully left. Add it again.
184
179
else {
185
- var newChildren = _ . merge ( this . state . children ) ;
186
- delete newChildren [ key ] ;
187
- this . setState ( { children : newChildren } ) ;
180
+ var newChildren = _ . filter ( this . state . children , function ( c ) { return key ( c ) !== leavekey ; } ) ;
181
+ this . setState ( { children : newChildren } ) ;
188
182
}
189
183
190
184
this . _tryFinish ( )
191
185
} ,
192
186
193
187
render : function ( ) {
194
- var childrenToRender = { } ;
195
-
196
-
197
- for ( var key in this . state . children ) {
198
-
199
- var child = this . state . children [ key ] ;
200
-
201
- if ( child ) {
202
- childrenToRender [ key ] = cloneWithProps (
203
- this . props . childFactory ( child ) ,
204
- { ref : key }
205
- ) ;
206
- }
207
- }
208
-
209
- return transferPropsTo ( this . props , this . props . component ( null , childrenToRender ) ) ;
188
+ var Component = this . props . component
189
+ return transferPropsTo ( this . props ,
190
+ Component ( null , this . state . children . map ( function ( c ) { return this . props . childFactory ( c , key ( c ) ) ; } . bind ( this ) ) ) ) ;
210
191
}
211
192
} ) ;
193
+
194
+ function getChild ( children ) {
195
+ return React . Children . only ( children )
196
+ }
197
+
198
+ //CHANGE 0.12.0
199
+ function key ( child ) {
200
+ return child && ( startsWith ( React . version , '0.12' ) ? child . key : child . props . key )
201
+ }
0 commit comments