All files / molecule/modal/src/hooks useDelayedRender.js

71.42% Statements 25/35
45% Branches 9/20
75% Functions 3/4
78.12% Lines 25/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66    1x 84x 84x 84x 84x 84x 84x   84x 3x   2x 2x   2x   2x                           1x   1x     1x     1x 1x 1x 1x 1x             84x 3x     3x     84x              
import {useCallback, useRef, useState} from 'react'
 
const useDelayedRender = (isActive, {enterDelay = 0, onEnterDelayed, exitDelay = 0, onExitDelayed}) => {
  const [, forceRender] = useState()
  const isMounted = useRef(isActive)
  const isRendered = useRef(false)
  const renderTimer = useRef(null)
  const unmountTimer = useRef(null)
  const previousIsActive = useRef(isActive)
 
  const update = useCallback(() => {
    if (previousIsActive.current) {
      // Mount immediately
      isMounted.current = true
      Iif (unmountTimer.current) clearTimeout(unmountTimer.current)
 
      Eif (enterDelay <= 0) {
        // Render immediately
        isRendered.current = true
      } else {
        if (renderTimer.current) return null
 
        // Render after a delay
        renderTimer.current = setTimeout(() => {
          isRendered.current = true
          renderTimer.current = null
          forceRender({})
          typeof onEnterDelayed === 'function' && onEnterDelayed()
        }, enterDelay)
      }
    } else {
      // Immediately set to un-rendered
      isRendered.current = false
 
      Iif (exitDelay <= 0) {
        isMounted.current = false
      } else {
        Iif (unmountTimer.current) return null
 
        // Unmount after a delay
        unmountTimer.current = setTimeout(() => {
          isMounted.current = false
          unmountTimer.current = null
          forceRender({})
          typeof onExitDelayed === 'function' && onExitDelayed()
        }, exitDelay)
      }
    }
  }, [enterDelay, onEnterDelayed, exitDelay, onExitDelayed])
 
  // When the active prop changes, need to update
  if (isActive !== previousIsActive.current) {
    previousIsActive.current = isActive
    // We want to do this synchronously with the render, not in an effect
    // this way when isActive → true, isMounted → true in the same pass
    update()
  }
 
  return {
    isMounted: isMounted.current,
    isRendered: isRendered.current
  }
}
 
export default useDelayedRender