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

Lodash Debounce在React组件中失效:多次触发而非仅执行一次

React防抖失效问题:输入时多次触发函数

当前输入框每输入一个字符,Testrender组件内的函数会在1秒后触发,且连续输入时会多次调用。需求是用户输入结束后仅调用一次,但目前输入过程中就多次触发,同时组件传值时防抖函数无延迟,达不到预期效果。

现有代码

Main_page组件

import { useState } from "react";
import Input from "./Input";
import Testrender from "./Testrender";

const Main_page = () => {
  const [count, setCount] = useState("");

  return (
    <>
      <Input count={count} setCount={setCount} />
      <Testrender count={count} />
    </>
  );
};

export default Main_page;

Input组件

import React from "react";

interface Props {
  count: string;
  setCount: (searchString: string) => void;
}

const Input = ({ count, setCount }: Props) => {
  return (
    <div>
      <input
        className="test-input"
        value={count}
        onChange={(e) => setCount(e.target.value)}
        placeholder="test render"
      />
    </div>
  );
};

export default Input;

Testrender组件(原问题代码)

import React, { useCallback, useEffect } from "react";
import { debounce } from "lodash";

interface Props {
  count: string;
}

const Testrender = ({ count }: Props) => {
  const request = debounce((stateValue: any) => {
    console.log("render");
  }, 1000);

  const changes = useCallback(request, [count]);

  useEffect(() => {
    changes(count);
  }, [count]);

  return <div>index</div>;
};

export default Testrender;

问题原因

  1. 防抖函数重复创建:每次count变化导致Testrender重新渲染时,都会重新调用debounce生成新的防抖函数实例。新实例没有之前的计时状态,每次输入都会开启新的1秒延迟,最终多个延迟到期后都会触发,造成多次调用。
  2. useCallback依赖错误:把count作为useCallback的依赖,导致每次count变化都生成新的changes函数,相当于每次都是全新的防抖函数,完全失去防抖作用。

修复方案

核心是让防抖函数保持唯一实例,避免每次渲染重新创建。以下是两种可行的修改方式:

方式一:防抖函数定义在组件外部

import React, { useEffect, useRef } from "react";
import { debounce } from "lodash";

interface Props {
  count: string;
}

// 防抖函数定义在组件外部,确保全局唯一实例
const debouncedRequest = debounce((stateValue: string) => {
  console.log("render", stateValue);
}, 1000);

const Testrender = ({ count }: Props) => {
  // 用useRef保存防抖函数实例,避免组件内重复创建
  const requestRef = useRef(debouncedRequest);

  useEffect(() => {
    // 每次count变化时调用防抖函数,连续输入会重置延迟
    requestRef.current(count);
    
    // 组件卸载时取消未执行的调用,防止内存泄漏
    return () => {
      requestRef.current.cancel();
    };
  }, [count]);

  return <div>index</div>;
};

export default Testrender;

方式二:用useRef在组件内初始化防抖函数

import React, { useEffect, useRef } from "react";
import { debounce } from "lodash";

interface Props {
  count: string;
}

const Testrender = ({ count }: Props) => {
  // 用useRef存储防抖函数实例,只初始化一次
  const requestRef = useRef<ReturnType<typeof debounce>>();

  if (!requestRef.current) {
    requestRef.current = debounce((stateValue: string) => {
      console.log("render", stateValue);
    }, 1000);
  }

  useEffect(() => {
    requestRef.current!(count);
    
    return () => {
      requestRef.current!.cancel();
    };
  }, [count]);

  return <div>index</div>;
};

export default Testrender;

关键说明

  • 两种方式都确保了防抖函数只有一个实例,连续输入时会自动重置延迟计时,最终只在输入停止1秒后触发一次。
  • 加入了组件卸载时的清理逻辑,调用cancel()取消未执行的防抖调用,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Виктория

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 18:03:27