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

是否有更优方案实现延迟更新数据的自定义React Hook?

优化防抖Hook的实现方案

你的防抖Hook实现可以进一步简化,不需要借助useRef来控制onUpdate的执行时机。核心思路是直接在防抖定时器的回调中同时完成值更新和回调触发,避免额外的状态监听和ref标记。

优化后的代码

import { useState, useEffect } from "react";

const useDebounce = (value, delay, onUpdate) => {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const timeoutId = setTimeout(() => {
      // 同时更新防抖值并触发回调
      setDebouncedValue(value);
      onUpdate?.(value);
    }, delay);

    return () => clearTimeout(timeoutId);
  }, [value, delay, onUpdate]);

  return debouncedValue;
};

export default useDebounce;

优化说明

  1. 移除冗余的useRef和第二个useEffect:原代码中用shouldUpdate标记是否触发回调,现在直接在定时器回调里执行onUpdate,逻辑更紧凑,减少了不必要的状态监听。
  2. 可选链处理onUpdate:用onUpdate?.(value)避免onUpdate未传入时的报错,提升鲁棒性。
  3. 依赖项完整:将onUpdate加入useEffect的依赖数组,确保回调更新时能正确触发防抖逻辑(如果onUpdate是动态生成的,建议在调用Hook时用useCallback包裹,避免不必要的定时器重置)。

额外优化:控制初始触发

如果需要避免初始值加载时触发onUpdate,可以添加一个skipInitial参数:

import { useState, useEffect, useRef } from "react";

const useDebounce = (value, delay, onUpdate, skipInitial = true) => {
  const [debouncedValue, setDebouncedValue] = useState(value);
  const isFirstRender = useRef(skipInitial);

  useEffect(() => {
    const timeoutId = setTimeout(() => {
      setDebouncedValue(value);
      if (!isFirstRender.current) {
        onUpdate?.(value);
      }
      isFirstRender.current = false;
    }, delay);

    return () => clearTimeout(timeoutId);
  }, [value, delay, onUpdate]);

  return debouncedValue;
};

这里仅在首次渲染时跳过onUpdate,后续值变化正常触发防抖回调。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 05:27:19