这个系列是将 ahooks 里面的所有 hook 源码都进行解读,通过解读 ahooks 的源码来熟悉自定义 hook 的写法,提高自己写自定义 hook 的能力,希望能够对大家有所帮助。
为了和代码原始注释区分,个人理解部分使用 ///开头,此处和 三斜线指令没有关系,只是为了做区分。
往期回顾
- ahooks 源码解读系列
- ahooks 源码解读系列 - 2
- ahooks 源码解读系列 - 3
- ahooks 源码解读系列 - 4
- ahooks 源码解读系列 - 5
- ahooks 源码解读系列 - 6
周一适合干什么?当然是先来一篇提神醒脑的 ahooks 源码解读啦~ 今天进入 SideEffect 部分的 ahooks。
SideEffect
useDebounceFn
对 lodash.debounce 的封装
import debounce from 'lodash.debounce';
import { useRef } from 'react';
import useCreation from '../useCreation';
import { DebounceOptions } from '../useDebounce/debounceOptions';
import useUnmount from '../useUnmount';
type Fn = (...args: any) => any;
function useDebounceFn<T extends Fn>(fn: T, options?: DebounceOptions) {
const fnRef = useRef<T>(fn);
fnRef.current = fn;
const wait = options?.wait ?? 1000;
/// 将目标方法转为 debounce 版本
const debounced = useCreation(
() =>
debounce<T>(
((...args: any[]) => {
return fnRef.current(...args);
}) as T,
wait,
options,
),
[],
);
useUnmount(() => {
debounced.cancel();
});
return {
run: (debounced as unknown) as T,
cancel: debounced.cancel,
flush: debounced.flush,
};
}
export default useDebounceFn;
useDebounce
将普通值转化为带有防抖行为的值
import { useState, useEffect } from 'react';
import useDebounceFn from '../useDebounceFn';
import { DebounceOptions } from './debounceOptions';
function useDebounce<T>(value: T, options?: DebounceOptions) {
const [debounced, setDebounced] = useState(value);
/// 将更新状态的方法改为防抖方法
const { run } = useDebounceFn(() => {
setDebounced(value);
}, options);
useEffect(() => {
run();
}, [value]);
return debounced;
}
export default useDebounce;
useThrottleFn
对 lodash.throttle 的封装
import throttle from 'lodash.throttle';
import { useRef } from 'react';
import useCreation from '../useCreation';
import { ThrottleOptions } from '../useThrottle/throttleOptions';
import useUnmount from '../useUnmount';
type Fn = (...args: any) => any;
function useThrottleFn<T extends Fn>(fn: T, options?: ThrottleOptions) {
const fnRef = useRef<T>(fn);
fnRef.current = fn;
const wait = options?.wait ?? 1000;
/// 将目标方法转化为节流版本
const throttled = useCreation(
() =>
throttle<T>(
((...args: any[]) => {
return fnRef.current(...args);
}) as T,
wait,
options,
),
[],
);
useUnmount(() => {
throttled.cancel();
});
return {
run: (throttled as unknown) as T,
cancel: throttled.cancel,
flush: throttled.flush,
};
}
export default useThrottleFn;
useThrottle
将普通值转化为带有节流行为的值
import { useState, useEffect } from 'react';
import useThrottleFn from '../useThrottleFn';
import { ThrottleOptions } from './throttleOptions';
function useThrottle<T>(value: T, options?: ThrottleOptions) {
const [throttled, setThrottled] = useState(value);
/// 将更新值的方法节流化
const { run } = useThrottleFn(() => {
setThrottled(value);
}, options);
useEffect(() => {
run();
}, [value]);
return throttled;
}
export default useThrottle;
useInterval、useTimeout
“会帮你擦屁股的定时器”
import { useEffect, useRef } from 'react';
function useInterval(
fn: () => void,
delay: number | null | undefined,
options?: {
immediate?: boolean;
},
): void {
const immediate = options?.immediate;
const fnRef = useRef<() => void>();
fnRef.current = fn;
useEffect(() => {
if (delay === undefined || delay === null) return;
if (immediate) {
fnRef.current?.();
}
const timer = setInterval(() => {
fnRef.current?.();
}, delay);
return () => {
/// 再也不用担心忘了清除定时器了
clearInterval(timer);
};
}, [delay]);
}
export default useInterval;
import { useEffect } from 'react';
import usePersistFn from '../usePersistFn';
function useTimeout(fn: () => void, delay: number | null | undefined): void {
const timerFn = usePersistFn(fn);
useEffect(() => {
if (delay === undefined || delay === null) return;
const timer = setTimeout(() => {
timerFn();
}, delay);
return () => {
/// 再也不用担心忘了清除定时器了
clearTimeout(timer);
};
}, [delay, timerFn]);
}
export default useTimeout;
以上内容由于本人水平问题难免有误,欢迎大家进行讨论反馈。