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

React中useRef与useMemo实现防抖:两种写法差异解析

React防抖实现中两种写法的差异解析

先看你的代码实现:

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

function debounce(fn) {
    let timer = null;
    return function () {
        clearTimeout(timer);
        timer = setTimeout(fn, 1000)
    }
}

export default function () {

    const [value, setValue] = useState("");
    const myRef = useRef(handlChangeUtil);

    //打印state的值
    //闭包:该函数捕获了'value'
    function handlChangeUtil() {
        console.log(value);
    }


    //将handlChangeUtil的最新版本绑定到myRef
    //因为首次挂载的函数无法获取更新后的value值
    useEffect(() => {
        myRef.current = handlChangeUtil;
    }, [value]);

    //仅在组件挂载时返回防抖函数

    const handlChangeUtilDebounce = useMemo(() => {

        //这段代码可以正常运行
        // const func = () => {
        //     myRef.current();
        // }

        // return debounce(func)

        //这段代码无法正常运行
        return debounce(myRef.current);
    } , []);


    function handleChange(e) {
        setValue(e.target.value);
        handlChangeUtilDebounce();
    }

    return (
        <div>
            <input value={value} onChange={handleChange} />
        </div>
    )

}

两种写法的核心差异在于debounce函数捕获的是哪个函数:

1. 直接传入myRef.current的写法(无法正常运行)

因为useMemo的依赖是空数组,所以只会在组件首次挂载时执行一次。此时myRef.current是组件第一次渲染时生成的handlChangeUtil函数——这个函数通过闭包捕获了初始的value(空字符串)。

之后虽然useEffect会在value变化时把myRef.current更新为新的handlChangeUtil(每次value变化都会生成新的函数,捕获当前最新的value),但debounce内部保存的fn还是首次传入的那个旧函数。当防抖触发时,执行的是旧的handlChangeUtil,自然只会打印初始的空字符串。

2. 包裹一层匿名函数的写法(正常运行)

这里传给debounce的是一个匿名函数() => { myRef.current(); },useMemo同样只在首次挂载时把这个匿名函数传给debounce。但这个匿名函数本身不会捕获固定的value,它只有在执行时才会去读取myRef.current的最新值——也就是useEffect更新后的、捕获了当前最新value的handlChangeUtil函数。所以每次防抖触发时,执行的都是最新的handlChangeUtil,能正确打印更新后的value。

简单来说,第一种写法让debounce记住了旧的函数,第二种写法让debounce记住的是一个“动态取最新函数”的逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 04:32:50