react的hooks防抖和节流是怎样做的

一、先给面试官的"标准定义"(先声夺人)

防抖(debounce) :在事件触发一段时间后才执行,期间再次触发会重新计时
节流(throttle):在固定时间内只执行一次

这一句一定要先说。


二、为什么在 React Hooks 里要"特别处理"?

问题本质:闭包 + 重新渲染

复制代码
const fn = () => {
  console.log(count)
}
  • 每次 render 都是新函数

  • 定时器 / 事件里用的可能是旧状态

👉 普通 JS 防抖在 Hooks 里会失效或拿到旧值


三、Hooks 防抖(推荐实现)

1️⃣ 最稳方案:useRef + useCallback

复制代码
function useDebounceFn(fn, delay = 300) {
  const timer = useRef<number | null>(null)
  const fnRef = useRef(fn)

  // 始终指向最新 fn,解决闭包问题
  fnRef.current = fn

  const debounce = useCallback((...args) => {
    if (timer.current) {
      clearTimeout(timer.current)
    }

    timer.current = window.setTimeout(() => {
      fnRef.current(...args)
    }, delay)
  }, [delay])

  return debounce
}

使用方式

复制代码
const onSearch = useDebounceFn(value => {
  fetchList(value)
}, 500)

<input onChange={e => onSearch(e.target.value)} />

2️⃣ 面试官加分点

使用 useRef 保存最新函数,避免闭包导致状态不更新。


四、Hooks 节流(两种方式都要会)


方案一:时间戳节流(最稳定)

复制代码
function useThrottleFn(fn, delay = 300) {
  const lastTime = useRef(0)
  const fnRef = useRef(fn)

  fnRef.current = fn

  return useCallback((...args) => {
    const now = Date.now()

    if (now - lastTime.current >= delay) {
      lastTime.current = now
      fnRef.current(...args)
    }
  }, [delay])
}

方案二:定时器节流(常被追问)

复制代码
function useThrottleFn(fn, delay = 300) {
  const timer = useRef<number | null>(null)
  const fnRef = useRef(fn)

  fnRef.current = fn

  return useCallback((...args) => {
    if (timer.current) return

    timer.current = window.setTimeout(() => {
      fnRef.current(...args)
      timer.current = null
    }, delay)
  }, [delay])
}

两种节流的区别(面试官爱问)

方式 特点
时间戳 立即执行
定时器 延迟执行

五、为什么不用 lodash debounce?

可以用,但要说清楚限制

复制代码
const debouncedFn = useMemo(
  () => debounce(fn, 300),
  []
)

❌ 问题:

  • fn 变了,debounce 不更新

  • 容易产生脏数据

正确用法

复制代码
const fnRef = useRef(fn)
fnRef.current = fn

const debounced = useMemo(
  () => debounce((...args) => fnRef.current(...args), 300),
  []
)

六、Hooks 防抖节流常见坑(必背)

❌ 错误写法

复制代码
const fn = debounce(() => {
  setCount(count + 1)
}, 300)

问题

  • 每次 render 都创建新 debounce

  • count 永远是旧值


✅ 正确认知

  • 防抖节流函数要只创建一次

  • 执行的函数要始终是最新的


七、什么时候用防抖?什么时候用节流?

防抖(Debounce)

  • 搜索框

  • 输入联想

  • 表单校验

节流(Throttle)

  • 滚动

  • resize

  • 拖拽


八、面试终极总结(一定要背)

React Hooks 下实现防抖节流,关键不是 setTimeout,而是用 useRef 解决闭包问题,保证函数引用稳定且状态最新。


相关推荐
ywf121531 分钟前
前端的dist包放到后端springboot项目下一起打包
前端·spring boot·后端
恋猫de小郭39 分钟前
2026,Android Compose 终于支持 Hot Reload 了,但是收费
android·前端·flutter
hpoenixf7 小时前
2026 年前端面试问什么
前端·面试
还是大剑师兰特7 小时前
Vue3 中的 defineExpose 完全指南
前端·javascript·vue.js
泯泷7 小时前
阶段一:从 0 看懂 JSVMP 架构,先在脑子里搭出一台最小 JSVM
前端·javascript·架构
mengchanmian8 小时前
前端node常用配置
前端
华洛8 小时前
利好打工人,openclaw不是企业提效工具,而是个人助理
前端·javascript·产品经理
xkxnq8 小时前
第六阶段:Vue生态高级整合与优化(第93天)Element Plus进阶:自定义主题(变量覆盖)+ 全局配置与组件按需加载优化
前端·javascript·vue.js
A黄俊辉A9 小时前
vue css中 :global的使用
前端·javascript·vue.js
小码哥_常9 小时前
被EdgeToEdge适配折磨疯了,谁懂!
前端