forked from 77media/video-flow
58 lines
1.3 KiB
TypeScript
58 lines
1.3 KiB
TypeScript
import { useEffect, useRef, EffectCallback, DependencyList } from "react";
|
|
|
|
type Mode = "debounce" | "throttle" | "none";
|
|
|
|
interface Options {
|
|
mode?: Mode;
|
|
delay?: number; // 毫秒
|
|
}
|
|
|
|
/**
|
|
* useUpdateEffect - 统一版
|
|
* 1. 跳过首次执行
|
|
* 2. 可选防抖/节流
|
|
*/
|
|
export function useUpdateEffect(
|
|
effect: EffectCallback,
|
|
deps: DependencyList,
|
|
options: Options = { mode: "none", delay: 0 }
|
|
) {
|
|
const { mode = "none", delay = 0 } = options;
|
|
const isFirstRender = useRef(true);
|
|
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
const lastRunTimeRef = useRef<number>(0);
|
|
|
|
useEffect(() => {
|
|
if (isFirstRender.current) {
|
|
isFirstRender.current = false;
|
|
return;
|
|
}
|
|
|
|
if (mode === "none" || delay <= 0) {
|
|
return effect();
|
|
}
|
|
|
|
if (mode === "debounce") {
|
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
timerRef.current = setTimeout(() => {
|
|
effect();
|
|
}, delay);
|
|
}
|
|
|
|
if (mode === "throttle") {
|
|
const now = Date.now();
|
|
if (now - lastRunTimeRef.current >= delay) {
|
|
effect();
|
|
lastRunTimeRef.current = now;
|
|
}
|
|
}
|
|
|
|
return () => {
|
|
if (mode === "debounce" && timerRef.current) {
|
|
clearTimeout(timerRef.current);
|
|
}
|
|
};
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, deps);
|
|
}
|