React16常用自定义Hooks封装

/* eslint-disable import/prefer-default-export */
import { useState, useRef, useEffect, useReducer } from 'react';

type noop = () => void;

/**
 * @description 强制重渲染 
 */
export const useForceUpdate = () => {
  const [, forceUpdate] = useReducer(s => s + 1, 0);
  return forceUpdate;
};

/*
 * @description 针对多层嵌套的 state 合并更新可用
 * @params defaultState 默认一层及以上的对象
 */
export const useLegacyState = <T,>(defaultState: T) => {
  let [state, setState] = useState(defaultState);

  const setLegacyState = (nextState: Partial<T>) => {
    let newState = { ...state, ...nextState };
    setState(newState);
  };

  return [state, setLegacyState];
};

/*
 * @description 只在更新时运行的 effect
 * @params callback 执行的函数
 */
export const useOnlyUpdateEffect = (callback: noop) => {
  let isUpdateRef = useRef(false);

  useEffect(() => {
    if (isUpdateRef.current) {
      callback && callback();
    }
    if (!isUpdateRef.current) {
      isUpdateRef.current = true;
    }
  });
};

/**
 * @description 节流
 * @param fn 回调函数
 * @param ms 时间
 * @param deps 依赖列表
 */
export const useThrottle = (fn: noop, ms = 30, deps: any[] = []) => {
  let previous = useRef(0);
  let [time, setTime] = useState(ms);
  useEffect(() => {
    let now = Date.now();
    if (now - previous.current > time) {
      fn();
      previous.current = now;
    }
  }, deps);

  const cancel = () => {
    setTime(0);
  };

  return [cancel];
};

/**
 * @description 防抖
 * @param fn 回调函数
 * @param ms 时间
 * @param deps 依赖列表
 */
export const useDebounce = (fn: noop, ms = 30, deps: any[] = []) => {
  let timeout = useRef<NodeJS.Timeout>();
  useEffect(() => {
    if (timeout.current) {
      clearTimeout(timeout.current);
    }
    timeout.current = setTimeout(() => {
      fn();
    }, ms);
  }, deps);

  const cancel = () => {
    if (timeout.current) {
      clearTimeout(timeout.current);
    }
  };

  return [cancel];
};

/**
 * @description 倒计时组件
 * @param defaultText 倒计时默认文案
 * @param ms 时间
 */
export const useCountDown = (defaultText = '获取验证码', ms = 1000) => {
  let [countText, setCountText] = useState(defaultText);
  let [isActive, setActive] = useState(false);

  const startCountDown = () => {
    setActive(true);
    setCountText('60秒');
    let timer: NodeJS.Timeout | null = setInterval(() => {
      setCountText(prevCount => {
        let count = window.parseInt(prevCount);
        if (count - 1 < 0) {
          clearInterval(timer!);
          timer = null;
          setActive(false);
          return defaultText;
        }
        return `${count - 1}秒`;
      });
    }, ms);

    return () => {
      timer && clearInterval(timer);
      timer = null;
    };
  };

  return [isActive, countText, startCountDown];
};

你可能感兴趣的:(React)