Skip to content

Commit 1d83ac1

Browse files
authored
chore(TransitionGroup): remove deprecated lifecycle methods (#3970)
1 parent bd92e01 commit 1d83ac1

File tree

5 files changed

+88
-62
lines changed

5 files changed

+88
-62
lines changed

src/lib/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import makeDebugger from './makeDebugger'
22

33
export AutoControlledComponent from './AutoControlledComponent'
44
export ModernAutoControlledComponent from './ModernAutoControlledComponent'
5-
export { getChildMapping, mergeChildMappings } from './childMapping'
65
export * as childrenUtils from './childrenUtils'
76

87
export {

src/modules/Transition/TransitionGroup.js

Lines changed: 53 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
import _ from 'lodash'
22
import 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

159
const 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() {

src/lib/childMapping.js renamed to src/modules/Transition/utils/childMapping.js

File renamed without changes.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React from 'react'
2+
import Transition from '../Transition'
3+
4+
/**
5+
* Wraps a React element with a Transition component.
6+
*
7+
* @param {React.ReactElement} child
8+
* @param {Function} onHide
9+
* @param {Object} [options={}]
10+
* @param {String} [options.animation]
11+
* @param {Number} [options.duration]
12+
* @param {Boolean} [options.directional]
13+
* @param {Boolean} [options.transitionOnMount=false]
14+
* @param {Boolean} [options.visible=true]
15+
*/
16+
export default function wrapChild(child, onHide, options = {}) {
17+
const { key } = child
18+
const { animation, directional, duration, transitionOnMount = false, visible = true } = options
19+
20+
return (
21+
<Transition
22+
animation={animation}
23+
directional={directional}
24+
duration={duration}
25+
key={key}
26+
onHide={onHide}
27+
reactKey={key}
28+
transitionOnMount={transitionOnMount}
29+
visible={visible}
30+
>
31+
{child}
32+
</Transition>
33+
)
34+
}

test/specs/lib/childMapping-test.js renamed to test/specs/modules/Transition/utils/childMapping-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react'
2-
import { getChildMapping, mergeChildMappings } from 'src/lib'
2+
import { getChildMapping, mergeChildMappings } from 'src/modules/Transition/utils/childMapping'
33

44
describe('childMapping', () => {
55
describe('childMapping', () => {

0 commit comments

Comments
 (0)