首页 > 解决方案 > 如何编写一个依赖于反应道具的计时器间隔?

问题描述

我正在为我的网站创建一个简单的弹出窗口组件,并且我想定期收集大约每秒左右的任何新消息或传入消息,以实现实时消息传递功能。我目前正在为我的项目使用 react。

我的主要问题是,我只想在名为“active”的道具设置为 True 时收集消息,但我不知道该怎么做。

这是我的网页模型,希望能有所帮助。它是网页的模型,包含三个条目,其中一个带有打开的消息窗口。

我有多个条目可以打开它们的消息窗口,但我已经传递了其他道具,因此一次只能打开一个消息窗口。因此,可以在组件的祖先之一中使用间隔/计时器,但我想通过自己调用 API 来使这个弹出窗口更加自给自足。

我尝试使用 setInterval 函数,该函数在消息窗口组件内的 useEffect 函数中进行初始化:

    let my_interval = useRef() // ???? Don't think this is the solution

    const timerHandler = useCallback(() => {
        // Some call to my RestAPI here.
        console.log("Timer called")
    }, active)

    // If the "active" prop turns true, the interval should be running. Else, clear the interval if it exists.
    // Here, the trouble is the interval handle "my_interval" is changing so I can't clear the original interval.
    useEffect(() => {
        if (active) my_interval = setInterval(timerHandler, 1000);
        else if (!active) clearInterval(my_interval)
    }, [active])

但是,正如评论指出的那样,我实际上无法清除间隔,因为我找不到使间隔句柄 my_interval 足够稳定的方法(useRef 不起作用)

我还尝试使用带有递归调用的超时函数,只要 active 为真,它就会继续调用自己,但我认为我有一个类似的问题,因为函数本身正在改变,所以递归调用有点坏了。

    // Only do action when active is set to true. This doesn't work, when active changes to false the timer still runs.
    const timeoutHandler = useCallback(() => { 
        if (active) console.log("Timer called")
        setTimeout(timeoutHandler, 1000);
    }, [active])

    // Set a timeout on render, regardless of "active"
    useEffect(() => {
        setTimeout(timeoutHandler, 1000);
    }, [])

任何帮助或不同的策略将不胜感激,我真的希望我的信使弹出窗口能够自给自足,它自己调用我的 RestAPI,但在这一点上似乎几乎不可能。

标签: reactjstimersetintervalreact-props

解决方案


useRef是一个对象,请参阅其 API 文档:

const intervalRef = useRef();

// handle on active state change
useEffect(() => {
  if (active) {
    intervalRef.current = setInterval(() => {
      console.log("Timer called");
    }, 1000);
  } else {
    clearInterval(intervalRef.current);
  }
}, [active]);

// handle unmount
useEffect(() => {
  const intervalId = intervalRef.current;
  return () => {
    clearInterval(intervalId);
  };
}, []);

推荐阅读