一些自用的自定义Hook

109 阅读2分钟

在react的学习和工作中,经常会用到Hook,但是react官方提供的Hook不满足业务需求咋办,这个时候就要去自定义一些hook了,本篇记录一下我自己有用到的一些自定义Hook,需者自取,长期更新哟!

Hook的规则

既然我们要在react中使用自定义的Hook,那么就必须遵循react对Hook制定的规则,Hook规则总共有两条

  1. 只在最顶层使用 Hook
  2. 只在 React 函数中调用 Hook

这可不是我乱说的哦,请看文档

1667983871385.png react官方对自定义Hook也有约束

自定义 Hook 是一个函数,其名称以 “use” 开头,函数内部可以调用其他的 Hook

如果我们在开发中不小心写错了,没有遵循这个约束,不用担心,react也会贴心的给我们报错

1667984556566.png

useHover(鼠标悬停)

function useHover() {
  const [flag, setFlag] = useState(false);
  const ref = useRef(null);

  const changeState = (e) => {
    if(e.type === 'mouseenter') {
      setFlag(true);
    } else {
      setFlag(false);
    }
  };

  useEffect(() => {
    let dom = ref?.current;
    if(dom) {
      dom.addEventListener('mouseenter', changeState);
      dom.addEventListener('mouseleave', changeState);
    }
    return () => {
      dom.removeEventListener('mouseenter', changeState);
      dom.removeEventListener('mouseleave', changeState);
      dom = null;
    };
  }, [ref]);
  return [ref, flag];
};

用法

export default function HoverHook() {

  const [ref, isHover] = useHover();

  return (
    <div ref={ref}>
      {isHover ? '悬' : '没悬'}
    </div>
  )
}

useFirstScreen(浏览器滚动超过首屏)

function useFirstScreen() {

  const [past, setPast] = useState(false);

  useEffect(() => {
    let windowHei = window.innerHeight;
    const listenScroll = () => {
      const top = Math.round(document.documentElement.scrollTop);
      if(top >= windowHei && !past) setPast(true);
      else if(top < windowHei && past) setPast(false);
    };
    const listenSize = () => {
      windowHei = window.innerHeight;
      listenScroll();
    };
    window.addEventListener('scroll', listenScroll, true);
    window.addEventListener('resize', listenSize);
    return () => {
      window.removeEventListener('scroll', listenScroll, true);
      window.removeEventListener('resize', listenSize);
    }
  }, [past]);

  return past;
}

用法

export default function FirstScreenHook() {
  const flag = useFirstScreen();
  return (
    <div>
      {
        flag ? <div>回到顶部</div> : <></>
      }
    </div>
  )
}

useCountdown(倒计时)

import { useState, useRef, useEffect } from "react";

export default function useCountdown(totalTime = 60, wait = 1000) {
    /**
     * totalTime:倒计时,总时长,正整数
     * wait:每次计时的延迟时间,毫秒数
     */
    const [lastTime, setLastTime] = useState(totalTime);
    const interval = useRef({});
    useEffect(() => {
        if(lastTime === 0) {
            clearInterval(interval.current);
            setLastTime(totalTime);
        }
        return () => {};
    }, [lastTime]);

    const start = () => {
        if(lastTime === 0 || lastTime === totalTime) {
            setLastTime(lt => lt -= 1);
            interval.current = setInterval(() => {
                setLastTime(lt => lt -= 1);
            }, wait);
        }
    };
    /**
     * 第一项为当前是否在计时状态
     * 第二项为当前剩余时长
     * 第三项为启动计时函数
     */
    return [lastTime === 0 || lastTime === totalTime, lastTime, start];
}

用法

const [flag, date, func] = useCountdown(60, 500);
<button className="count-down" onClick={() => func()}>
    倒计时
    {
        !flag && <div className="btn-mask">{date}</div>
    }
</button>

截屏2022-12-14 15.46.45.png