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

在setInterval中传递箭头函数与函数引用的差异及问题排查

setInterval传递箭头函数与函数引用的差异分析

问题

请问在setInterval中传递箭头函数和传递函数引用是否存在差异?即setInterval(callbackRef.current, 5000)与setInterval(() => callbackRef.current(), 5000)这两种写法有何不同?为何我的代码中只有第二种写法生效,第一种写法会在回调函数中输出旧值?

上下文代码

const MyPage = (callback, delay): void => {
  const savedCallbackRef = useRef(callback)

  useEffect((): void => {
    savedCallbackRef.current = callback
  }, [callback])

  useEffect(() => {
    if (delay != null) {
      const id = setInterval(savedCallbackRef.current, delay)
      return () => clearInterval(id)
    }
   
  }, [delay])
}

更新示例

useInterval 钩子

const useInterval = (callback, delay): void => {
  const savedCallbackRef = useRef(callback)

  useEffect((): void => {
    savedCallbackRef.current = callback
  }, [callback])

  useEffect(() => {
    if (delay != null) {
      const id = setInterval(savedCallbackRef.current, delay)
      return () => clearInterval(id)
    }
   
  }, [delay])
}

组件使用

const MyApp = ({ loading }) => {
  useInterval(() => {
     if (!loading) {
        // do something
     }
  }, 500)
}

差异分析与原因

核心差异:函数引用的捕获时机

  • 直接传递函数引用:setInterval(savedCallbackRef.current, delay)会在useEffect执行的瞬间,捕获当前savedCallbackRef.current指向的函数引用,并将这个固定的引用绑定给定时器。后续即使savedCallbackRef.current被更新为新的函数,定时器依然只会调用最初捕获的旧函数。
  • 箭头函数包裹:setInterval(() => savedCallbackRef.current(), delay)中,定时器捕获的是箭头函数的引用。每次定时器触发时,才会动态读取savedCallbackRef.current的最新值,并调用这个最新的函数。

结合你的代码逻辑解释

在useInterval钩子中:

  1. 第一个useEffect会在传入的callback更新时,同步将savedCallbackRef.current替换为最新的回调函数。
  2. 第二个useEffect仅依赖delay,只有当delay变化时才会重新执行,创建新的定时器。

当MyApp中的loading状态改变时,传给useInterval的回调会变成一个新的箭头函数(组件每次渲染都会生成新的箭头函数),此时第一个useEffect会更新savedCallbackRef.current为新函数。但第二个useEffect因delay未变化不会重新执行,旧定时器依然持有最初的回调引用,导致执行时使用旧的loading逻辑;而箭头函数包裹的写法,每次触发都会取最新的savedCallbackRef.current,自然能拿到包含最新loading状态的回调。

修正方案

将第二个useEffect中的setInterval改为箭头函数包裹的形式即可:

useEffect(() => {
  if (delay != null) {
    const id = setInterval(() => savedCallbackRef.current(), delay)
    return () => clearInterval(id)
  }
}, [delay])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 11:00:11