有时候,我们需要在 React 组件里,做一些防抖、节流处理。
这篇文章,让我们一起来看看怎么通过 React Hook 形式写防抖、节流。
利用 Lodash 的 Throttle 函数
lodash 的 throttle 函数,可以在固定的时间限制函数执行。
对应实例,我们可以这样写:
import React, { useEffect, useRef, useState } from "react";
import { throttle } from "lodash";
export default function App() {
const [value, setValue] = useState(0);
const throttled = useRef(throttle((newValue) => console.log(newValue), 1000));
useEffect(() => throttled.current(value), [value]);
return <button onClick={() => setValue(value + 1)}>{value}</button>;
}
因为 throttle 函数执行间隔是单位是毫秒,所以我们的函数会在 1000 毫秒内只执行一次。
我们利用 useRef 的设置 throttle 可以利用 throttle.current 的形式直接使用。
throttle 会把函数缓存起来,在重新 render 时,我们不会重复创建函数。
然后,我们创建一个 useEffect 并调用函数,当我们点击这个按钮时,我们可以看到 throttled 函数只执行一次。
利用 useCallback 来存储 Throttle
我们可以使用 useCallback 来替换 useRef
对应实例,我们可以这样写:
import React, { useCallback, useEffect, useState } from "react";
import { throttle } from "lodash";
export default function App() {
const [value, setValue] = useState(0);
const throttled = useCallback(
throttle((newValue) => console.log(newValue), 1000),
[]
);
useEffect(() => throttled(value), [value]);
return <button onClick={() => setValue(value + 1)}>{value}</button>;
}
我们可以通过 useCallbacl 将 throttle 的函数缓存起来,避免 render 时,重复创建。
可以得到上一个例子一样的结果
防抖
防抖函数,意味着我们的代码将被延迟执行。
我们可以自己写一个 hook:
import React, { useCallback, useEffect, useState } from "react";
const useDebouncedEffect = (effect, delay, deps) => {
const callback = useCallback(effect, deps);
useEffect(() => {
const handler = setTimeout(() => {
callback();
}, delay);
return () => {
clearTimeout(handler);
};
}, [callback, delay]);
};
export default function App() {
const [value, setValue] = useState(0);
useDebouncedEffect(() => console.log(value), 1000, [value]);
return <button onClick={() => setValue(value + 1)}>{value}</button>;
}
useDebouncedEffect 是通过在 useEffect 中利用 setTimeout 来执行回调。
我们调用的回调函数,是从传入的 effect。
在组件 redner 时,因为我们是使用 useCallback 缓存了 effect,所以我们不会重复创建函数。
deps 被 useCallback 监听了,所以 deps 发生改变时,函数会重新创建。
setTimeout 返回了一个时间对象,所以在组件卸载时,我们可以利用它清除 setTimeout。
当我们组件卸载时,我们通过 clearTimeout 来清除计时器。
在 App 组件中,我们利用 useDebouncedEffect 来延迟执行我们的函数。
现在,我们点击按钮,直到我们等待 1000 毫秒,函数将会被执行。
总结
看会了吗?看会了,我们可以很轻易的在 React 中使用防抖节流。
核心是函数缓存和延迟执行,函数缓存通过 useCallback 和 uesRef 来实现。