Something this simple should be easily accomplished, yet I\'m pulling my hair out over how complicated it is.
All I want to do is animate the mounting & unmounti
If I use Velocity or AnimeJS library to animate node directly (instead of css or setTimeout), then I found out I can design a hook to provide the animation status on and function onToggle to kick off the animation (ex. slidedown, fade).
Basically what the hook does is to toggle on and off the animation, and afterwards update the on accordingly. Therefore we can get the status of the animation accurately. Without doing so would reply on a ad-hoc duration.
/**
* A hook to provide animation status.
* @class useAnimate
* @param {object} _ props
* @param {async} _.animate Promise to perform animation
* @param {object} _.node Dom node to animate
* @param {bool} _.disabled Disable animation
* @returns {useAnimateObject} Animate status object
* @example
* const { on, onToggle } = useAnimate({
* animate: async () => { },
* node: node
* })
*/
import { useState, useCallback } from 'react'
const useAnimate = ({
animate, node, disabled,
}) => {
const [on, setOn] = useState(false)
const onToggle = useCallback(v => {
if (disabled) return
if (v) setOn(true)
animate({ node, on: v }).finally(() => {
if (!v) setOn(false)
})
}, [animate, node, disabled, effect])
return [on, onToggle]
}
export default useAnimate
The usage is the following,
const ref = useRef()
const [on, onToggle] = useAnimate({
animate: animateFunc,
node: ref.current,
disabled
})
const onClick = () => { onToggle(!on) }
return (
{on && }
)
and the animate implementation could be,
import anime from 'animejs'
const animateFunc = (params) => {
const { node, on } = params
const height = on ? 233 : 0
return new Promise(resolve => {
anime({
targets: node,
height,
complete: () => { resolve() }
}).play()
})
}