7
7
import React from 'react'
8
8
import ReactDOM from 'react-dom'
9
9
import PropTypes from 'prop-types'
10
+ import chain from 'chain-function'
11
+ import warning from 'warning'
10
12
11
13
import ReactCSSTransitionGroupChild from 'react-transition-group/CSSTransitionGroupChild'
12
14
import { nameShape , transitionTimeout } from 'react-transition-group/utils/PropTypes'
@@ -42,11 +44,17 @@ export default class ReactCSSTransitionReplace extends React.Component {
42
44
childComponent : 'span' ,
43
45
}
44
46
45
- state = {
46
- currentKey : '1' ,
47
- currentChild : this . props . children ? React . Children . only ( this . props . children ) : undefined ,
48
- prevChildren : { } ,
49
- height : null ,
47
+ constructor ( props , context ) {
48
+ super ( props , context )
49
+
50
+ this . childRefs = Object . create ( null )
51
+
52
+ this . state = {
53
+ currentKey : '1' ,
54
+ currentChild : this . props . children ? React . Children . only ( this . props . children ) : undefined ,
55
+ prevChildren : { } ,
56
+ height : null ,
57
+ }
50
58
}
51
59
52
60
componentWillMount ( ) {
@@ -73,8 +81,7 @@ export default class ReactCSSTransitionReplace extends React.Component {
73
81
return
74
82
}
75
83
76
- const { state} = this
77
- const { currentKey} = state
84
+ const { currentKey, prevChildren} = this . state
78
85
79
86
const nextState = {
80
87
currentKey : String ( Number ( currentKey ) + 1 ) ,
@@ -87,9 +94,9 @@ export default class ReactCSSTransitionReplace extends React.Component {
87
94
}
88
95
89
96
if ( currentChild ) {
90
- nextState . height = ReactDOM . findDOMNode ( this . refs [ currentKey ] ) . offsetHeight
97
+ nextState . height = ReactDOM . findDOMNode ( this . childRefs [ currentKey ] ) . offsetHeight
91
98
nextState . prevChildren = {
92
- ...state . prevChildren ,
99
+ ...prevChildren ,
93
100
[ currentKey ] : currentChild ,
94
101
}
95
102
if ( ! this . transitioningKeys [ currentKey ] ) {
@@ -113,7 +120,7 @@ export default class ReactCSSTransitionReplace extends React.Component {
113
120
114
121
performAppear ( key ) {
115
122
this . transitioningKeys [ key ] = true
116
- this . refs [ key ] . componentWillAppear ( this . handleDoneAppearing . bind ( this , key ) )
123
+ this . childRefs [ key ] . componentWillAppear ( this . handleDoneAppearing . bind ( this , key ) )
117
124
}
118
125
119
126
handleDoneAppearing = ( key ) => {
@@ -126,7 +133,7 @@ export default class ReactCSSTransitionReplace extends React.Component {
126
133
127
134
performEnter ( key ) {
128
135
this . transitioningKeys [ key ] = true
129
- this . refs [ key ] . componentWillEnter ( this . handleDoneEntering . bind ( this , key ) )
136
+ this . childRefs [ key ] . componentWillEnter ( this . handleDoneEntering . bind ( this , key ) )
130
137
this . enqueueHeightTransition ( )
131
138
}
132
139
@@ -143,7 +150,7 @@ export default class ReactCSSTransitionReplace extends React.Component {
143
150
144
151
performLeave = ( key ) => {
145
152
this . transitioningKeys [ key ] = true
146
- this . refs [ key ] . componentWillLeave ( this . handleDoneLeaving . bind ( this , key ) )
153
+ this . childRefs [ key ] . componentWillLeave ( this . handleDoneLeaving . bind ( this , key ) )
147
154
if ( ! this . state . currentChild ) {
148
155
// The enter transition dominates, but if there is no
149
156
// entering component the height is set to zero.
@@ -156,6 +163,7 @@ export default class ReactCSSTransitionReplace extends React.Component {
156
163
157
164
const nextState = { prevChildren : { ...this . state . prevChildren } }
158
165
delete nextState . prevChildren [ key ]
166
+ delete this . childRefs [ key ]
159
167
160
168
if ( ! this . state . currentChild ) {
161
169
nextState . height = null
@@ -170,14 +178,14 @@ export default class ReactCSSTransitionReplace extends React.Component {
170
178
if ( ! state . currentChild ) {
171
179
return this . setState ( { height : 0 } )
172
180
}
173
- this . setState ( { height : ReactDOM . findDOMNode ( this . refs [ state . currentKey ] ) . offsetHeight } )
181
+ this . setState ( { height : ReactDOM . findDOMNode ( this . childRefs [ state . currentKey ] ) . offsetHeight } )
174
182
} , TICK )
175
183
}
176
184
177
185
wrapChild ( child , moreProps ) {
178
186
let transitionName = this . props . transitionName
179
187
180
- if ( typeof transitionName == 'object' && transitionName !== null ) {
188
+ if ( typeof transitionName === 'object' && transitionName !== null ) {
181
189
transitionName = { ...transitionName }
182
190
delete transitionName . height
183
191
}
@@ -209,7 +217,7 @@ export default class ReactCSSTransitionReplace extends React.Component {
209
217
} = this . props
210
218
211
219
if ( height !== null ) {
212
- const heightClassName = ( typeof transitionName == 'object' && transitionName !== null )
220
+ const heightClassName = ( typeof transitionName === 'object' && transitionName !== null )
213
221
? transitionName . height || ''
214
222
: `${ transitionName } -height`
215
223
@@ -227,6 +235,12 @@ export default class ReactCSSTransitionReplace extends React.Component {
227
235
}
228
236
229
237
Object . keys ( prevChildren ) . forEach ( key => {
238
+ const child = prevChildren [ key ]
239
+ const isCallbackRef = typeof child . ref !== 'string'
240
+ warning ( isCallbackRef ,
241
+ 'string refs are not supported on children of ReactCSSTransitionReplace and will be ignored. ' +
242
+ 'Please use a callback ref instead: https://facebook.github.io/react/docs/refs-and-the-dom.html#the-ref-callback-attribute' )
243
+
230
244
childrenToRender . push (
231
245
React . createElement ( childComponent ,
232
246
{
@@ -240,19 +254,38 @@ export default class ReactCSSTransitionReplace extends React.Component {
240
254
} ,
241
255
} ,
242
256
this . wrapChild (
243
- typeof prevChildren [ key ] . type == 'string'
244
- ? prevChildren [ key ]
245
- : React . cloneElement ( prevChildren [ key ] , { isLeaving : true } ) ,
246
- { ref : key } )
257
+ typeof child . type !== 'string'
258
+ ? React . cloneElement ( child , { isLeaving : true } )
259
+ : child ,
260
+ {
261
+ ref : chain (
262
+ isCallbackRef ? child . ref : null ,
263
+ ( r ) => { this . childRefs [ key ] = r }
264
+ ) ,
265
+ }
266
+ )
247
267
)
248
268
)
249
269
} )
250
270
251
271
if ( currentChild ) {
272
+ const isCallbackRef = typeof currentChild . ref !== 'string'
273
+ warning ( isCallbackRef ,
274
+ 'string refs are not supported on children of ReactCSSTransitionReplace and will be ignored. ' +
275
+ 'Please use a callback ref instead: https://facebook.github.io/react/docs/refs-and-the-dom.html#the-ref-callback-attribute' )
276
+
252
277
childrenToRender . push (
253
278
React . createElement ( childComponent ,
254
279
{ key : currentKey } ,
255
- this . wrapChild ( currentChild , { ref : currentKey } )
280
+ this . wrapChild (
281
+ currentChild ,
282
+ {
283
+ ref : chain (
284
+ isCallbackRef ? currentChild . ref : null ,
285
+ ( r ) => { this . childRefs [ currentKey ] = r }
286
+ ) ,
287
+ }
288
+ )
256
289
)
257
290
)
258
291
}
0 commit comments