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

在Debounce防抖函数中无法获取自定义Hook数据的原因是什么

import { debounce  } from 'lodash';
import { useState, useCallback } from 'react';

const App = () => {
  const [text, setText] = useTestState();

  const handleSearchKeyword = (keyword: string) => {
    setText(keyword);
    sendQuery();
  };

  const sendQuery = useCallback(
    debounce(() => {
      console.log(text);
    }, 1000),
    []
  );

  return <input type="text" onChange={handleSearchKeyword} />;
};

const useTestState = () => {
  const [text, setText] = useState('');

  return [text, setText];
};

根本原因

这个问题本质是React的闭包陷阱,和自定义Hook没有关系,核心问题出在useCallback和debounce的组合使用上:

  • 你给useCallback传了空的依赖数组,这意味着sendQuery函数只会在组件首次渲染时创建1次,后续组件无论怎么重渲染,sendQuery都永远是首次渲染生成的那个版本
  • 首次渲染时,text的初始值是空字符串(你观测到的null是初始值配置差异),防抖回调捕获的永远是首次渲染上下文中的text变量,后续text更新之后,旧闭包里的text还是原来的初始值,所以打印出来不符合预期。

可行的解决方案

方案1:给useCallback补充text依赖

每次text更新时重新生成防抖函数,就能拿到最新的状态值,这个方案适配搜索防抖的场景,连续输入时防抖会自动重置,符合预期:

const sendQuery = useCallback(
  debounce(() => {
    console.log(text);
  }, 1000),
  [text]
);

方案2:用useRef存储最新状态

用ref保存状态的最新引用,不受闭包限制,不需要修改useCallback的依赖:

const App = () => {
  const [text, setText] = useTestState();
  // 用ref同步最新的text值
  const textRef = useRef(text);
  useEffect(() => {
    textRef.current = text;
  }, [text])

  const handleSearchKeyword = (keyword: string) => {
    setText(keyword);
    sendQuery();
  };

  const sendQuery = useCallback(
    debounce(() => {
      console.log(textRef.current);
    }, 1000),
    []
  );

  return <input type="text" onChange={handleSearchKeyword} />;
};

方案3(最推荐):直接传参给防抖函数

不需要在防抖回调中读取状态,直接把最新的关键词作为参数传入,完全规避闭包问题,性能最优:

const handleSearchKeyword = (keyword: string) => {
  setText(keyword);
  sendQuery(keyword);
};

const sendQuery = useCallback(
  debounce((latestKeyword) => {
    console.log(latestKeyword);
  }, 1000),
  []
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 07:57:04