Skip to content

Commit

Permalink
chore(Transition): remove deprecated lifecycle methods (#3982)
Browse files Browse the repository at this point in the history
* chore(Transition): remove deprecated lifecycle methods

* fix coverage, remove useless branches

* revert change in example
  • Loading branch information
layershifter committed Jul 11, 2020
1 parent 20d851d commit ee9a7c7
Show file tree
Hide file tree
Showing 4 changed files with 363 additions and 226 deletions.
5 changes: 3 additions & 2 deletions src/addons/TransitionablePortal/TransitionablePortal.js
Expand Up @@ -4,6 +4,7 @@ import React, { Component } from 'react'

import Portal from '../Portal'
import Transition from '../../modules/Transition'
import { TRANSITION_STATUS_ENTERING } from '../../modules/Transition/utils/computeStatuses'
import { getUnhandledProps, makeDebugger } from '../../lib'

const debug = makeDebugger('transitionable_portal')
Expand Down Expand Up @@ -117,7 +118,7 @@ export default class TransitionablePortal extends Component {
debug('handleTransitionStart()')
const { portalOpen } = this.state
const { status } = data
const transitionVisible = status === Transition.ENTERING
const transitionVisible = status === TRANSITION_STATUS_ENTERING

_.invoke(this.props, 'onStart', null, { ...data, portalOpen, transitionVisible })

Expand All @@ -134,7 +135,7 @@ export default class TransitionablePortal extends Component {

render() {
debug('render()', this.state)
// console.log('render', this.state)

const { children, transition } = this.props
const { portalOpen, transitionVisible } = this.state

Expand Down
186 changes: 70 additions & 116 deletions src/modules/Transition/Transition.js
Expand Up @@ -5,12 +5,25 @@ import { cloneElement, Component } from 'react'

import { makeDebugger, normalizeTransitionDuration, SUI, useKeyOnly } from '../../lib'
import TransitionGroup from './TransitionGroup'
import {
computeStatuses,
TRANSITION_STATUS_ENTERED,
TRANSITION_STATUS_ENTERING,
TRANSITION_STATUS_EXITED,
TRANSITION_STATUS_EXITING,
TRANSITION_STATUS_INITIAL,
TRANSITION_STATUS_UNMOUNTED,
} from './utils/computeStatuses'

const debug = makeDebugger('transition')

const TRANSITION_TYPE = {
ENTERING: 'show',
EXITING: 'hide',
const TRANSITION_CALLBACK_TYPE = {
[TRANSITION_STATUS_ENTERED]: 'show',
[TRANSITION_STATUS_EXITED]: 'hide',
}
const TRANSITION_STYLE_TYPE = {
[TRANSITION_STATUS_ENTERING]: 'show',
[TRANSITION_STATUS_EXITING]: 'hide',
}

/**
Expand Down Expand Up @@ -94,96 +107,84 @@ export default class Transition extends Component {
unmountOnHide: false,
}

static ENTERED = 'ENTERED'
static ENTERING = 'ENTERING'
static EXITED = 'EXITED'
static EXITING = 'EXITING'
static UNMOUNTED = 'UNMOUNTED'
/** @deprecated Static properties will be removed in v1 */
static INITIAL = TRANSITION_STATUS_INITIAL
static ENTERED = TRANSITION_STATUS_ENTERED
static ENTERING = TRANSITION_STATUS_ENTERING
static EXITED = TRANSITION_STATUS_EXITED
static EXITING = TRANSITION_STATUS_EXITING
static UNMOUNTED = TRANSITION_STATUS_UNMOUNTED

static Group = TransitionGroup

constructor(...args) {
super(...args)

const { initial: status, next } = this.computeInitialStatuses()
this.nextStatus = next
this.state = { status }
state = {
status: TRANSITION_STATUS_INITIAL,
}

// ----------------------------------------
// Lifecycle
// ----------------------------------------

componentDidMount() {
debug('componentDidMount()')

this.updateStatus()
}
static getDerivedStateFromProps(props, state) {
const derivedState = computeStatuses({
mountOnShow: props.mountOnShow,
status: state.status,
transitionOnMount: props.transitionOnMount,
visible: props.visible,
unmountOnHide: props.unmountOnHide,
})

// eslint-disable-next-line camelcase
UNSAFE_componentWillReceiveProps(nextProps) {
debug('componentWillReceiveProps()')
debug('getDerivedStateFromProps()', props, state, derivedState)

const { current: status, next } = this.computeStatuses(nextProps)
return derivedState
}

this.nextStatus = next
if (status) this.setState({ status })
componentDidMount() {
debug('componentDidMount()')
this.updateStatus({})
}

componentDidUpdate() {
componentDidUpdate(prevProps, prevState) {
debug('componentDidUpdate()')

this.updateStatus()
this.updateStatus(prevState)
}

componentWillUnmount() {
debug('componentWillUnmount()')

clearTimeout(this.timeoutId)
}

// ----------------------------------------
// Callback handling
// ----------------------------------------

handleStart = () => {
handleStart = (nextStatus) => {
const { duration } = this.props
const status = this.nextStatus

this.nextStatus = null
this.setState({ status, animating: true }, () => {
const durationType = TRANSITION_TYPE[status]
const durationValue = normalizeTransitionDuration(duration, durationType)
const durationType = TRANSITION_CALLBACK_TYPE[nextStatus]
const durationValue = normalizeTransitionDuration(duration, durationType)

_.invoke(this.props, 'onStart', null, { ...this.props, status })
this.timeoutId = setTimeout(this.handleComplete, durationValue)
})
clearTimeout(this.timeoutId)
this.timeoutId = setTimeout(
() => this.setState((state) => ({ status: state.nextStatus })),
durationValue,
)
}

handleComplete = () => {
const { status: current } = this.state

_.invoke(this.props, 'onComplete', null, { ...this.props, status: current })

if (this.nextStatus) {
this.handleStart()
return
updateStatus = (prevState) => {
if (this.state.status !== this.state.nextStatus && this.state.nextStatus) {
this.handleStart(this.state.nextStatus)
}

const status = this.computeCompletedStatus()
const callback = current === Transition.ENTERING ? 'onShow' : 'onHide'

this.setState({ status, animating: false }, () => {
_.invoke(this.props, callback, null, { ...this.props, status })
})
}
if (!prevState.animating && this.state.animating) {
_.invoke(this.props, 'onStart', null, { ...this.props, status: this.state.status })
}

updateStatus = () => {
const { animating } = this.state
if (prevState.animating && !this.state.animating) {
const callback = this.state.status === TRANSITION_STATUS_ENTERED ? 'onShow' : 'onHide'

if (this.nextStatus) {
this.nextStatus = this.computeNextStatus()
if (!animating) this.handleStart()
_.invoke(this.props, 'onComplete', null, { ...this.props, status: this.state.status })
_.invoke(this.props, callback, null, { ...this.props, status: this.state.status })
}
}

Expand All @@ -205,72 +206,23 @@ export default class Transition extends Component {
animation,
childClasses,
useKeyOnly(animating, 'animating'),
useKeyOnly(status === Transition.ENTERING, 'in'),
useKeyOnly(status === Transition.EXITING, 'out'),
useKeyOnly(status === Transition.EXITED, 'hidden'),
useKeyOnly(status !== Transition.EXITED, 'visible'),
useKeyOnly(status === TRANSITION_STATUS_ENTERING, 'in'),
useKeyOnly(status === TRANSITION_STATUS_EXITING, 'out'),
useKeyOnly(status === TRANSITION_STATUS_EXITED, 'hidden'),
useKeyOnly(status !== TRANSITION_STATUS_EXITED, 'visible'),
'transition',
)
}

return cx(animation, childClasses, useKeyOnly(animating, 'animating transition'))
}

computeCompletedStatus = () => {
const { unmountOnHide } = this.props
const { status } = this.state

if (status === Transition.ENTERING) return Transition.ENTERED
return unmountOnHide ? Transition.UNMOUNTED : Transition.EXITED
}

computeInitialStatuses = () => {
const { visible, mountOnShow, transitionOnMount, unmountOnHide } = this.props

if (visible) {
if (transitionOnMount) {
return {
initial: Transition.EXITED,
next: Transition.ENTERING,
}
}
return { initial: Transition.ENTERED }
}

if (mountOnShow || unmountOnHide) return { initial: Transition.UNMOUNTED }
return { initial: Transition.EXITED }
}

computeNextStatus = () => {
const { animating, status } = this.state

if (animating) return status === Transition.ENTERING ? Transition.EXITING : Transition.ENTERING
return status === Transition.ENTERED ? Transition.EXITING : Transition.ENTERING
}

computeStatuses = (props) => {
const { status } = this.state
const { visible } = props

if (visible) {
return {
current: status === Transition.UNMOUNTED && Transition.EXITED,
next:
status !== Transition.ENTERING && status !== Transition.ENTERED && Transition.ENTERING,
}
}

return {
next: (status === Transition.ENTERING || status === Transition.ENTERED) && Transition.EXITING,
}
}

computeStyle = () => {
const { children, duration } = this.props
const { status } = this.state

const childStyle = _.get(children, 'props.style')
const type = TRANSITION_TYPE[status]
const type = TRANSITION_STYLE_TYPE[status]
const animationDuration = type && `${normalizeTransitionDuration(duration, type)}ms`

return { ...childStyle, animationDuration }
Expand All @@ -281,14 +233,16 @@ export default class Transition extends Component {
// ----------------------------------------

render() {
debug('render()')
debug('props', this.props)
debug('state', this.state)
debug('render(): props', this.props)
debug('render(): state', this.state)

const { children } = this.props
const { status } = this.state

if (status === Transition.UNMOUNTED) return null
if (status === TRANSITION_STATUS_UNMOUNTED) {
return null
}

return cloneElement(children, {
className: this.computeClasses(),
style: this.computeStyle(),
Expand Down

0 comments on commit ee9a7c7

Please sign in to comment.