React - animate mount and unmount of a single component

前端 未结 16 1783
南笙
南笙 2020-12-22 16:34

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

16条回答
  •  长情又很酷
    2020-12-22 17:19

    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()
      })
    }
    
    

提交回复
热议问题