Sweet HOCs: withEnterTransition
A super simple Higher-Order Component to add a mounting transition to any component.
If you’ve ever wanted to create a cute mounting animation to delight your users, we’ve got a great solution for you. Our solution today will use React-Pose by Popmotion in conjunction with Recompose and Ramda to create a HOC that implements an animation.
Let’s dive in!
// withEnterTransition.jsimport React from 'react'
import PropTypes from 'prop-types'
import { omit } from 'ramda'
import { compose, lifecycle, setPropTypes, withStateHandlers } from 'recompose'
import posed from 'react-pose'// Declare separate animation states
const poseProps = {
hidden: {
y: 10,
opacity: 0,
},
visible: {
y: 0,
opacity: 1,
}
}// Create animated wrapper
const PosedContainer = posed.div(poseProps)// Component with Animation
const withEnterTransition = BaseComponent => props => {
const baseProps = omit(['delay', 'poseState'], props)
return (
<PosedContainer pose={props.poseState}>
<BaseComponent {...baseProps} />
</PosedContainer>
)
}// Create props and prop change handlers to manage Pose State
const withState = withStateHandlers(
({ poseState = 'hidden' }) => ({
poseState,
}),
{
updatePose: ({ poseState }) => (nextPoseState) => ({
poseState: nextPoseState
}),
}
)// When the component mounts, after a timeout, update Pose state
const withLifecycle = lifecycle({
componentDidMount() {
setTimeout(() => {
this.props.updatePose('visible')
}, this.props.delay || 500)
}
})// Declare PropTypes
const withPropTypes = setPropTypes({
delay: PropTypes.number,
})export default compose(
withState,
withLifecycle,
withPropTypes,
withEnterTransition
)
Okay… I know that was intense. But if we break it down piece by piece, it starts to make sense.
First, to understand this example, you fundamentally have to understand how the React-Pose by Popmotion library works. All we have to do to trigger an animation is change the pose
props on the PosedContainer
to one of the designated states, and a transition will fire.
In this case, we change the opacity and y-position from (0, 10) to (1, 0), respectively.
Second, we create our own composed functionality called withState
that creates some local state and a local state change handler for updating the poseState
of a given component. We will soon apply this component to the PoseContainer
and lifecycle hooks.
Third, we create our own lifecycle hooks and use the componentDidMount
lifecycle method to trigger an animation after a specific timeout (the delay
prop).
Fourth, we enhance our base component with the necessary delay
PropType.
Lastly, we compose all our HOCs together to apply them to a base component!
Using Our HOC
It’s actually super straightforward.
// Example.jsimport React from 'react'
import { compose } from 'recompose'
import withEnterTransition from './withEnterTransition'const Example = props => <h1>{props.title}</h1>export default compose(withEnterTransition)(Example)
Kaboom!
Now when we use the <Example delay={1000} title="Hello, world!" />
component in the rest of our code, the component will fade in and up after a delay of 1s.