import { useEffect, useState } from 'react'; export default function useDebounce(text: string, delay: number) { const [value, setValue] = useState(''); useEffect(() => { const timerId = setTimeout(() => { setValue(text); }, delay); return () => { clearTimeout(timerId); }; }, [text, delay]); return value; }
我曾经制作和使用 useDebounce
钩子。
但是,在调整大小事件中使用 useDebounce
存在一些问题。
useDebounce hook
必须在组件顶部运行,因为它在内部使用了 useEffect。
但是,调整大小函数设置为在 useEffect 上运行,如下所示。
此外,上面的代码将值作为一个因素,但我认为我们需要接收它作为回调才能使用下面的代码。
useEffect(() => { const handler = () => { if (liRef.current) setWidth(liRef.current.clientWidth); }; window.addEventListener('resize', handler); return () => window.removeEventListener('resize', handler); }, []);
如何使用上面的代码来利用现有的useDebounce?
P粉0984172232024-01-29 11:40:03
如果你直接在React组件中使用debounced函数,它将不起作用,因为每个渲染都会创建一个新函数,相反,你可以使用这个useDebounce
钩子:
function useDebounce(callback, delay) { const callbackRef = React.useRef(callback) React.useLayoutEffect(() => { callbackRef.current = callback }) return React.useMemo( () => debounce((...args) => callbackRef.current(...args), delay), [delay], ) }
useRef
确保它与上次提供的函数相同,并且 useLayoutEffect
确保在每次渲染时,对函数的引用都会更新。
有关这方面的更多信息,请参阅“最新参考”模式反应
P粉8940084902024-01-29 09:59:42
我认为与其通过useEffect
实现去抖,不如将去抖逻辑实现为一个函数。
useEffect
当deps
引用的状态改变时执行。也就是说,由于是一个如果只按照执行流程就容易漏掉的逻辑,所以后期维护时很难弄清楚这个useEffect
是从哪一个流程衍生出来的,调试起来也比较困难。
示例
自定义反跳
function debounce(func, timeout = 300) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => { func.apply(this, args); }, timeout); }; }
function saveInput() { console.log('Saving data'); } const processChange = debounce(() => saveInput());
如果您使用lodash
,则只需导入即可使用它。
Lodash Debounce
import { debounce } from 'lodash';
const debounceOnChange = debounce(() => { console.log("This is a debounce function"); }, 500);
希望这有帮助:)