You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React的resize事件中复用现有useDebounce钩子?

复用useDebounce钩子适配Resize事件的两种方案

原实现代码

现有的useDebounce钩子

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;
}

当前的Resize事件绑定代码

useEffect(() => {
  const handler = () => {
    if (liRef.current) setWidth(liRef.current.clientWidth);
  };

  window.addEventListener('resize', handler);
  return () => window.removeEventListener('resize', handler);
}, []);

方案1:不修改原钩子,通过中间状态适配

思路:用一个状态存储实时获取的宽度,将该状态传入原useDebounce得到防抖后的值,再监听防抖值更新最终状态。

步骤1:优化原钩子为泛型(可选,支持非字符串类型)

如果需要让原钩子支持数字等其他类型,修改为泛型版本:

import { useEffect, useState } from 'react';

export default function useDebounce<T>(value: T, delay: number) {
  const [debouncedValue, setDebouncedValue] = useState<T>(value);

  useEffect(() => {
    const timerId = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);
    return () => clearTimeout(timerId);
  }, [value, delay]);

  return debouncedValue;
}

步骤2:组件中使用

import useDebounce from './useDebounce';
import { useEffect, useState, useRef } from 'react';

function YourComponent() {
  const liRef = useRef<HTMLLIElement>(null);
  const [width, setWidth] = useState(0);
  // 存储实时宽度的中间状态
  const [rawWidth, setRawWidth] = useState(0);
  // 传入原useDebounce获取防抖后的值
  const debouncedWidth = useDebounce(rawWidth, 300);

  // 监听防抖值变化,更新最终状态
  useEffect(() => {
    setWidth(debouncedWidth);
  }, [debouncedWidth]);

  // 绑定Resize事件,更新实时宽度
  useEffect(() => {
    const handler = () => {
      if (liRef.current) {
        setRawWidth(liRef.current.clientWidth);
      }
    };

    window.addEventListener('resize', handler);
    return () => window.removeEventListener('resize', handler);
  }, []);

  return <li ref={liRef}>宽度:{width}px</li>;
}

方案2:基于原逻辑扩展防抖回调钩子

如果不想维护额外中间状态,可以基于原useDebounce的定时器逻辑,封装一个专门处理函数防抖的钩子。

扩展useDebounceCallback钩子

import { useEffect, useRef } from 'react';

// 基于原防抖逻辑封装的回调防抖钩子
export function useDebounceCallback<T extends (...args: any[]) => void>(callback: T, delay: number) {
  const callbackRef = useRef<T>(callback);

  // 更新回调引用,避免闭包问题
  useEffect(() => {
    callbackRef.current = callback;
  }, [callback]);

  return (...args: Parameters<T>) => {
    const timerId = setTimeout(() => {
      callbackRef.current(...args);
    }, delay);
    return () => clearTimeout(timerId);
  };
}

组件中使用

import { useDebounceCallback } from './useDebounceCallback';
import { useEffect, useState, useRef } from 'react';

function YourComponent() {
  const liRef = useRef<HTMLLIElement>(null);
  const [width, setWidth] = useState(0);

  // 创建防抖后的Resize处理函数
  const debouncedResizeHandler = useDebounceCallback(() => {
    if (liRef.current) {
      setWidth(liRef.current.clientWidth);
    }
  }, 300);

  // 绑定Resize事件
  useEffect(() => {
    window.addEventListener('resize', debouncedResizeHandler);
    return () => window.removeEventListener('resize', debouncedResizeHandler);
  }, [debouncedResizeHandler]);

  return <li ref={liRef}>宽度:{width}px</li>;
}

内容的提问来源于stack exchange,提问作者pvp11

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 01:24:29