Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(Transition): remove deprecated lifecycle methods #3982

Merged
merged 3 commits into from Jul 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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