11import _ from 'lodash'
22import PropTypes from 'prop-types'
3- import React , { cloneElement , Fragment } from 'react'
4-
5- import {
6- getChildMapping ,
7- getElementType ,
8- getUnhandledProps ,
9- makeDebugger ,
10- mergeChildMappings ,
11- SUI ,
12- } from '../../lib'
13- import Transition from './Transition'
3+ import React from 'react'
4+
5+ import { getElementType , getUnhandledProps , makeDebugger , SUI } from '../../lib'
6+ import { getChildMapping , mergeChildMappings } from './utils/childMapping'
7+ import wrapChild from './utils/wrapChild'
148
159const debug = makeDebugger ( 'transition_group' )
1610
@@ -43,46 +37,72 @@ export default class TransitionGroup extends React.Component {
4337 }
4438
4539 static defaultProps = {
46- as : Fragment ,
40+ as : React . Fragment ,
4741 animation : 'fade' ,
4842 duration : 500 ,
4943 }
5044
51- constructor ( ...args ) {
52- super ( ...args )
45+ state = {
46+ // Keeping a callback under the state is a hack to make it accessible under getDerivedStateFromProps()
47+ handleOnHide : ( nothing , childProps ) => {
48+ debug ( 'handleOnHide' , childProps )
49+ const { reactKey } = childProps
5350
54- const { children } = this . props
55- this . state = {
56- children : _ . mapValues ( getChildMapping ( children ) , ( child ) => this . wrapChild ( child ) ) ,
57- }
51+ this . setState ( ( state ) => {
52+ const children = { ...state . children }
53+ delete children [ reactKey ]
54+
55+ return { children }
56+ } )
57+ } ,
5858 }
5959
60- // eslint-disable-next-line camelcase
61- UNSAFE_componentWillReceiveProps ( nextProps ) {
62- debug ( 'componentWillReceiveProps()' )
60+ static getDerivedStateFromProps ( props , state ) {
61+ debug ( 'getDerivedStateFromProps()' )
62+
63+ const { animation, duration, directional } = props
64+ const { children : prevMapping } = state
65+
66+ // A short circuit for an initial render as there will be no `prevMapping`
67+ if ( typeof prevMapping === 'undefined' ) {
68+ return {
69+ children : _ . mapValues ( getChildMapping ( props . children ) , ( child ) =>
70+ wrapChild ( child , state . handleOnHide , {
71+ animation,
72+ duration,
73+ directional,
74+ } ) ,
75+ ) ,
76+ }
77+ }
6378
64- const { children : prevMapping } = this . state
65- const nextMapping = getChildMapping ( nextProps . children )
79+ const nextMapping = getChildMapping ( props . children )
6680 const children = mergeChildMappings ( prevMapping , nextMapping )
6781
6882 _ . forEach ( children , ( child , key ) => {
6983 const hasPrev = _ . has ( prevMapping , key )
7084 const hasNext = _ . has ( nextMapping , key )
85+
7186 const { [ key ] : prevChild } = prevMapping
7287 const isLeaving = ! _ . get ( prevChild , 'props.visible' )
7388
7489 // Heads up!
7590 // An item is new (entering), it will be picked from `nextChildren`, so it should be wrapped
7691 if ( hasNext && ( ! hasPrev || isLeaving ) ) {
77- children [ key ] = this . wrapChild ( child , { transitionOnMount : true } )
92+ children [ key ] = wrapChild ( child , state . handleOnHide , {
93+ animation,
94+ duration,
95+ directional,
96+ transitionOnMount : true ,
97+ } )
7898 return
7999 }
80100
81101 // Heads up!
82102 // An item is old (exiting), it will be picked from `prevChildren`, so it has been already
83103 // wrapped, so should be only updated
84104 if ( ! hasNext && hasPrev && ! isLeaving ) {
85- children [ key ] = cloneElement ( prevChild , { visible : false } )
105+ children [ key ] = React . cloneElement ( prevChild , { visible : false } )
86106 return
87107 }
88108
@@ -93,43 +113,16 @@ export default class TransitionGroup extends React.Component {
93113 props : { visible, transitionOnMount } ,
94114 } = prevChild
95115
96- children [ key ] = this . wrapChild ( child , { transitionOnMount, visible } )
116+ children [ key ] = wrapChild ( child , state . handleOnHide , {
117+ animation,
118+ duration,
119+ directional,
120+ transitionOnMount,
121+ visible,
122+ } )
97123 } )
98124
99- this . setState ( { children } )
100- }
101-
102- handleOnHide = ( nothing , childProps ) => {
103- debug ( 'handleOnHide' , childProps )
104- const { reactKey } = childProps
105-
106- this . setState ( ( state ) => {
107- const children = { ...state . children }
108- delete children [ reactKey ]
109-
110- return { children }
111- } )
112- }
113-
114- wrapChild = ( child , options = { } ) => {
115- const { animation, directional, duration } = this . props
116- const { key } = child
117- const { visible = true , transitionOnMount = false } = options
118-
119- return (
120- < Transition
121- animation = { animation }
122- directional = { directional }
123- duration = { duration }
124- key = { key }
125- onHide = { this . handleOnHide }
126- reactKey = { key }
127- transitionOnMount = { transitionOnMount }
128- visible = { visible }
129- >
130- { child }
131- </ Transition >
132- )
125+ return { children }
133126 }
134127
135128 render ( ) {
0 commit comments