All files / src/popover useDelayVisible.ts

100% Statements 17/17
80% Branches 4/5
100% Functions 7/7
100% Lines 16/16

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                                306x                 306x       306x 2x 2x 1x   2x 2x 2x   2x 2x 2x   2x       306x 271x       306x    
import { useRef, useEffect } from "react";
import { useDefaultValue } from "../form/controlled";
 
export interface DelayVisibleHookOption {
  visible?: boolean;
  defaultVisible?: boolean;
  onVisibleChange?: (visible: boolean) => void;
}
 
/**
 * @hooks
 *
 * 延迟设置可见值
 */
export function useDelayVisible(option: DelayVisibleHookOption) {
  // 让 visible 属性支持 default
  const { value: visible, onChange: onVisibleChange } = useDefaultValue(
    {
      defaultValue: option.defaultVisible,
      value: option.visible,
      onChange: option.onVisibleChange,
    },
    false
  );
 
  const lastTaskCancellation = useRef<() => void>(null);
 
  // 延时 timeout 再切换到新的状态,任务保存到 taskRef 中
  // 如果有新的变化,清空上次任务,重新开启新任务
  const setVisible = (nextVisible: boolean, delay = 0) =>
    new Promise<boolean>(resolve => {
      if (lastTaskCancellation.current) {
        lastTaskCancellation.current();
      }
      const timer = setTimeout(() => {
        onVisibleChange(nextVisible);
        resolve(true);
      }, delay);
      const cancel = () => {
        clearTimeout(timer);
        resolve(false);
      };
      lastTaskCancellation.current = cancel;
    });
 
  // unmout 的时候无论如何都清除任务
  useEffect(
    () => () => lastTaskCancellation.current && lastTaskCancellation.current(),
    []
  );
 
  return { visible, setVisible };
}