@@ -210,65 +210,71 @@ class Transition extends React.Component {
210
210
if ( nextStatus !== null ) {
211
211
// nextStatus will always be ENTERING or EXITING.
212
212
this . cancelNextCallback ( )
213
- const node = ReactDOM . findDOMNode ( this )
214
213
215
214
if ( nextStatus === ENTERING ) {
216
- this . performEnter ( node , mounting )
215
+ this . performEnter ( mounting )
217
216
} else {
218
- this . performExit ( node )
217
+ this . performExit ( )
219
218
}
220
219
} else if ( this . props . unmountOnExit && this . state . status === EXITED ) {
221
220
this . setState ( { status : UNMOUNTED } )
222
221
}
223
222
}
224
223
225
- performEnter ( node , mounting ) {
224
+ performEnter ( mounting ) {
226
225
const { enter } = this . props
227
226
const appearing = this . context ? this . context . isMounting : mounting
227
+ const [ maybeNode , maybeAppearing ] = this . props . nodeRef
228
+ ? [ appearing ]
229
+ : [ ReactDOM . findDOMNode ( this ) , appearing ]
228
230
229
231
const timeouts = this . getTimeouts ( )
230
232
const enterTimeout = appearing ? timeouts . appear : timeouts . enter
231
233
// no enter animation skip right to ENTERED
232
234
// if we are mounting and running this it means appear _must_ be set
233
235
if ( ( ! mounting && ! enter ) || config . disabled ) {
234
236
this . safeSetState ( { status : ENTERED } , ( ) => {
235
- this . props . onEntered ( node )
237
+ this . props . onEntered ( maybeNode )
236
238
} )
237
239
return
238
240
}
239
241
240
- this . props . onEnter ( node , appearing )
242
+ this . props . onEnter ( maybeNode , maybeAppearing )
241
243
242
244
this . safeSetState ( { status : ENTERING } , ( ) => {
243
- this . props . onEntering ( node , appearing )
245
+ this . props . onEntering ( maybeNode , maybeAppearing )
244
246
245
- this . onTransitionEnd ( node , enterTimeout , ( ) => {
247
+ this . onTransitionEnd ( enterTimeout , ( ) => {
246
248
this . safeSetState ( { status : ENTERED } , ( ) => {
247
- this . props . onEntered ( node , appearing )
249
+ this . props . onEntered ( maybeNode , maybeAppearing )
248
250
} )
249
251
} )
250
252
} )
251
253
}
252
254
253
- performExit ( node ) {
255
+ performExit ( ) {
254
256
const { exit } = this . props
255
257
const timeouts = this . getTimeouts ( )
258
+ const maybeNode = this . props . nodeRef
259
+ ? undefined
260
+ : ReactDOM . findDOMNode ( this )
256
261
257
262
// no exit animation skip right to EXITED
258
263
if ( ! exit || config . disabled ) {
259
264
this . safeSetState ( { status : EXITED } , ( ) => {
260
- this . props . onExited ( node )
265
+ this . props . onExited ( maybeNode )
261
266
} )
262
267
return
263
268
}
264
- this . props . onExit ( node )
269
+
270
+ this . props . onExit ( maybeNode )
265
271
266
272
this . safeSetState ( { status : EXITING } , ( ) => {
267
- this . props . onExiting ( node )
273
+ this . props . onExiting ( maybeNode )
268
274
269
- this . onTransitionEnd ( node , timeouts . exit , ( ) => {
275
+ this . onTransitionEnd ( timeouts . exit , ( ) => {
270
276
this . safeSetState ( { status : EXITED } , ( ) => {
271
- this . props . onExited ( node )
277
+ this . props . onExited ( maybeNode )
272
278
} )
273
279
} )
274
280
} )
@@ -308,8 +314,11 @@ class Transition extends React.Component {
308
314
return this . nextCallback
309
315
}
310
316
311
- onTransitionEnd ( node , timeout , handler ) {
317
+ onTransitionEnd ( timeout , handler ) {
312
318
this . setNextCallback ( handler )
319
+ const node = this . props . nodeRef
320
+ ? this . props . nodeRef . current
321
+ : ReactDOM . findDOMNode ( this )
313
322
314
323
const doesNotHaveTimeoutOrListener =
315
324
timeout == null && ! this . props . addEndListener
@@ -319,7 +328,10 @@ class Transition extends React.Component {
319
328
}
320
329
321
330
if ( this . props . addEndListener ) {
322
- this . props . addEndListener ( node , this . nextCallback )
331
+ const [ maybeNode , maybeNextCallback ] = this . props . nodeRef
332
+ ? [ this . nextCallback ]
333
+ : [ node , this . nextCallback ]
334
+ this . props . addEndListener ( maybeNode , maybeNextCallback )
323
335
}
324
336
325
337
if ( timeout != null ) {
@@ -349,6 +361,7 @@ class Transition extends React.Component {
349
361
delete childProps . onExit
350
362
delete childProps . onExiting
351
363
delete childProps . onExited
364
+ delete childProps . nodeRef
352
365
353
366
if ( typeof children === 'function' ) {
354
367
// allows for nested Transitions
@@ -370,6 +383,19 @@ class Transition extends React.Component {
370
383
}
371
384
372
385
Transition . propTypes = {
386
+ /**
387
+ * A React reference to DOM element that need to transition:
388
+ * https://stackoverflow.com/a/51127130/4671932
389
+ *
390
+ * - When `nodeRef` prop is used, `node` is not passed to callback functions
391
+ * (e.g. `onEnter`) because user already has direct access to the node.
392
+ * - When changing `key` prop of `Transition` in a `TransitionGroup` a new
393
+ * `nodeRef` need to be provided to `Transition` with changed `key` prop
394
+ * (see
395
+ * [test/CSSTransition-test.js](https://github.com/reactjs/react-transition-group/blob/13435f897b3ab71f6e19d724f145596f5910581c/test/CSSTransition-test.js#L362-L437)).
396
+ */
397
+ nodeRef : PropTypes . shape ( { current : PropTypes . instanceOf ( Element ) } ) ,
398
+
373
399
/**
374
400
* A `function` child can be used instead of a React element. This function is
375
401
* called with the current transition status (`'entering'`, `'entered'`,
@@ -466,7 +492,9 @@ Transition.propTypes = {
466
492
/**
467
493
* Add a custom transition end trigger. Called with the transitioning
468
494
* DOM node and a `done` callback. Allows for more fine grained transition end
469
- * logic. **Note:** Timeouts are still used as a fallback if provided.
495
+ * logic. Timeouts are still used as a fallback if provided.
496
+ *
497
+ * **Note**: when `nodeRef` prop is passed, `node` is not passed.
470
498
*
471
499
* ```jsx
472
500
* addEndListener={(node, done) => {
@@ -481,6 +509,8 @@ Transition.propTypes = {
481
509
* Callback fired before the "entering" status is applied. An extra parameter
482
510
* `isAppearing` is supplied to indicate if the enter stage is occurring on the initial mount
483
511
*
512
+ * **Note**: when `nodeRef` prop is passed, `node` is not passed.
513
+ *
484
514
* @type Function(node: HtmlElement, isAppearing: bool) -> void
485
515
*/
486
516
onEnter : PropTypes . func ,
@@ -489,6 +519,8 @@ Transition.propTypes = {
489
519
* Callback fired after the "entering" status is applied. An extra parameter
490
520
* `isAppearing` is supplied to indicate if the enter stage is occurring on the initial mount
491
521
*
522
+ * **Note**: when `nodeRef` prop is passed, `node` is not passed.
523
+ *
492
524
* @type Function(node: HtmlElement, isAppearing: bool)
493
525
*/
494
526
onEntering : PropTypes . func ,
@@ -497,27 +529,35 @@ Transition.propTypes = {
497
529
* Callback fired after the "entered" status is applied. An extra parameter
498
530
* `isAppearing` is supplied to indicate if the enter stage is occurring on the initial mount
499
531
*
532
+ * **Note**: when `nodeRef` prop is passed, `node` is not passed.
533
+ *
500
534
* @type Function(node: HtmlElement, isAppearing: bool) -> void
501
535
*/
502
536
onEntered : PropTypes . func ,
503
537
504
538
/**
505
539
* Callback fired before the "exiting" status is applied.
506
540
*
541
+ * **Note**: when `nodeRef` prop is passed, `node` is not passed.
542
+ *
507
543
* @type Function(node: HtmlElement) -> void
508
544
*/
509
545
onExit : PropTypes . func ,
510
546
511
547
/**
512
548
* Callback fired after the "exiting" status is applied.
513
549
*
550
+ * **Note**: when `nodeRef` prop is passed, `node` is not passed.
551
+ *
514
552
* @type Function(node: HtmlElement) -> void
515
553
*/
516
554
onExiting : PropTypes . func ,
517
555
518
556
/**
519
557
* Callback fired after the "exited" status is applied.
520
558
*
559
+ * **Note**: when `nodeRef` prop is passed, `node` is not passed
560
+ *
521
561
* @type Function(node: HtmlElement) -> void
522
562
*/
523
563
onExited : PropTypes . func ,
0 commit comments