自定义Hook

useDebounce

  • 防抖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import { useState, useEffect } from 'react'
    function useDebounce(value: any, delay = 300) {
    const [debouncedValue, setDebouncedValue] = useState(value)
    useEffect(() => {
    const handler = window.setTimeout(() => {
    setDebouncedValue(value)
    }, delay)
    return () => {
    clearTimeout(handler)
    }
    }, [value, delay])
    return debouncedValue
    }
    export default useDebounce;
  • 使用方式

    1
    2
    3
    import useDebounce from './useDebounce'
    const useDebounceValue = useDebounce(inputValue, 500)
    // 此时只要 把 之前的 表单value 全部换成 useDebounceValue就行了

useThrottle

  • 节流
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import {useEffect, useRef,useCallback} from 'react';
    function useThrottle(fn, delay, dep = []) {
    const { current } = useRef({ fn, timer: null });
    useEffect(function () {
    current.fn = fn;
    }, [fn]);

    return useCallback(function (...args) {
    if (!current.timer) {
    current.timer = setTimeout(() => {
    delete current.timer;
    }, delay);
    current.fn.call(this, ...args);
    }
    }, dep);
    }
    export default useThrottle
  • 使用方式
    1
    2
    import useThrottle from './useThrottle'
    const throttledFunc = useThrottle(fn, 2000);

useVirtualList

  • 虚拟列表

    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
    // 虚拟列表
    import { RefObject, useEffect, useState } from 'react'
    interface Args extends IntersectionObserverInit {
    freezeOnceVisible?: boolean
    }
    /**
    *
    * @param {ReactRef} elementRef 传入虚拟列表父盒子的 ref
    * @param {object}
    * threshold 阀值 0-1 1表示完全出现在屏幕可视区域才触发
    * root 表示指定根元素 默认为浏览器视口 用于检查目标可见性
    * rootMargin root的外边距 '0 0 0 0'
    * freezeOnceVisible 是否缓存 再次滑动不重新渲染
    * @returns {Object} entry 这个对象具有当前可视区的信息
    * 例如 entry.isIntersecting 是否在可视区范围
    */
    function useVirtualList(
    elementRef: RefObject<Element>,
    {
    threshold = 0,
    root = null,
    rootMargin = '0%',
    freezeOnceVisible = false
    }: Args
    ): IntersectionObserverEntry | undefined {

    const [entry, setEntry] = useState<IntersectionObserverEntry>()
    const frozen = entry?.isIntersecting && freezeOnceVisible
    const updateEntry = ([entry]: IntersectionObserverEntry[]): void => {
    setEntry(entry)
    }
    useEffect(() => {
    const node = elementRef?.current
    const hasIOSupport = !!window.IntersectionObserver
    if (!hasIOSupport || frozen || !node) return
    const observerParams = { threshold, root, rootMargin }
    const observer = new IntersectionObserver(updateEntry, observerParams)
    observer.observe(node)
    return () => observer.disconnect()
    }, [elementRef, JSON.stringify(threshold), root, rootMargin, frozen])

    return entry
    }
    export default useVirtualList
  • 使用方式

    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
    // 只要判断entry是true还是false就可以得知 他是不是在可视区了
    const Section = (props) => {
    const ref = useRef(null)
    const entry = useVirtualList(ref, {})
    // !! 将它转成布尔值
    const isVisible = !!entry?.isIntersecting
    console.log(`Render Section ${props.title}`, { isVisible })
    return (
    <div
    ref={ref}
    style={{
    minHeight: '100vh',
    display: 'flex',
    border: '1px dashed #000',
    fontSize: '2rem',
    width: '100%'
    }}
    >
    {
    isVisible ? (
    <div style={{ margin: 'auto' }}>{props.title}</div>
    ) : ""
    }
    </div>
    )
    }

    Array.from({ length: 100 }).map((_, index) => (
    <Section key={index + 1} title={`${index + 1}`} />
    ))

useScrollPostion

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 获取滚动条高度
import {useState,useEffect} from 'react'
function useScrollPostion() {
const [scrollPosition, setScrollPostion] = useState(0)
useEffect(() => {
const handleScroll = () => {
setScrollPostion(window.scrollY)
}
document.addEventListener('scroll', handleScroll);
return () => {
document.removeEventListener('scroll', handleScroll)
}
},[])
return scrollPosition
}
export default useScrollPostion
  • 使用方式
    1
    2
    import useScrollPostion form './useScrollPostion'
    const position = useScrollPostion()

useWinSize

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 获取屏幕尺寸
import { useState, useCallback, useEffect } from 'react'
function useWinSize() {
const [size, setSize] = useState({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
})
const onResize = useCallback(() => {
setSize({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
})
}, [])
useEffect(() => {
window.addEventListener('resize', onResize)
return () => {
window.removeEventListener('reisze', onResize)
}
}, [])
return size
}
export default useWinSize
  • 使用方式
    1
    2
    import useWinSize form './useWinSize'
    const size = useWinSize()

useIsVisible

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
// 是否在可视区
import { useState, useEffect } from "react";
const OPTIONS = {
root: null,
rootMargin: "0px 0px 0px 0px",
threshold: 0,
};

const useIsVisible = (elementRef) => {
const [isVisible, setIsVisible] = useState(false);

useEffect(() => {
if (elementRef.current) {
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setIsVisible(true);
observer.unobserve(elementRef.current);
}
});
}, OPTIONS);
observer.observe(elementRef.current);
}
}, [elementRef]);

return isVisible;
};
export default useIsVisible;
  • 使用方式
    1
    2
    3
    4
    const elemRef = useRef();
    const isVisible = useVisible(elemRef);
    <div style={{ height: "145vh", width: '100%' }}>1</div>
    <div ref={elemRef}>hello {isVisible && console.log("visible")}</div>

forceUpdate

1
2
3
4
5
6
const [ignored, forceUpdate] = useReducer(x => x + 1, 0);
function handleClick() {
forceUpdate();
}
// 使用方式
组件名.forceUpdate(callback)