【问题标题】:Javascript setInterval not detecting global variable change (React Native)Javascript setInterval 未检测到全局变量更改(React Native)
【发布时间】:2020-12-15 01:32:35
【问题描述】:

我正在开发一个用于与 BLE 设备通信的 React Native 应用程序。为了跟踪连接是否仍然建立,我在组件中使用了一个状态。

  const [isConnected, setIsConnected] = useState(props.route.params.isConnected || false);

在我的 useEffect 钩子中,我开始一个间隔来重复读取我的 BLE 设备的状态,如下所示:

  useEffect(() => {
    AppState.addEventListener('change', onAppStateChange);
    updateStatusRepeatedly.current = setInterval(readStatus, 5000);
    return () => {
      AppState.removeEventListener('change', onAppStateChange);
      clearInterval(updateStatusRepeatedly.current);
    };
  }, []);

readStatus 函数每 5 秒调用一次,它按预期工作。但是不应该执行的内容。所以我将它包装在一个基于isConnected 变量的条件语句中。

const readStatus = () => {
  if (isConnected) {
    readAddedCharge();
    readPowerMeasurement();
  } 
};

内容每次都会被执行。即使 isConnected 变量设置为 false。我不明白为什么,因为其他功能和组件正确考虑了isConnected

知道为什么其他函数和组件会注册 isConnected 的更改,而作为计时器调用的 readStatus 函数不会?

【问题讨论】:

  • Dan Abramov 可能会发现 this article 很有用,他创建了一个 useInterval() 钩子
  • @amik 为我提供了解决我问题的答案。但我肯定也会对此进行研究。谢谢。

标签: javascript reactjs timer scope closures


【解决方案1】:

这似乎是一个 React 的函数组件。让我们做一个最小的例子:

function MyComp() {
  const [foo, setFoo] = useState(0);
  useEffect(() => {
    setInterval(() => {
      console.log(foo); // this will always show 0
      setFoo(foo + 1);
    }, 5000);
  }, []);
}

因为在函数范围内,foo 是一个永远不会改变的const。 “更改” foo 意味着使用新值 foo 再次运行该函数,无论如何您都不会使用它,因为 useEffect(..., []) 仅在第一次渲染时被调用。

可能的解决方案:

  1. 清除并重新创建每个组件渲染的间隔
  2. useRef 存储值,以便第一次渲染的readStatus 始终引用最新值

【讨论】:

  • 我能够使用 useRef 挂钩解决问题。谢谢。
【解决方案2】:

我遇到了同样的问题,但找到了解决方案。我们创建了一个执行间隔的组件,它在事物的反应端调用一个外部函数。例如,请参见下面的代码。

   const intervalExample = () => {
     const [timeslots, setTimeslots] = useState([]);
     
     const loopingFunction = () => {
        if (timeslots.length > 0) {
            timeslots.map((val) => {
                if (val['purchasing'] == true) {                    
                    doStuff();
                }
            });
        }
    }

    const doStuff = () = >{
    }


     return <div><IntervalRunner onInterval={loopingFunction} milliseconds="5000" /></div>

}


const IntervalRunner = (props) => {
    const [increments, setIncrements] = useState(0);
    const intervalCall = () => {
        setIncrements(increments+1);
         
    }
    
    useEffect(()=>{
         props.onInterval();
         setTimeout(intervalCall, props.milliseconds)
    }
    , [increments])
     return '';
     
}

以上组件相当基础,可能需要改进。在最后几分钟,我意识到我们需要一个开/关开关。模组如下。

export const IntervalRunner = (props) => {
const [increments, setIncrements] = useState(0);
const intervalCall = () => {
    if(props.active){
        setIncrements(increments+1);
    }
     
}

useEffect(()=>{
     if(props.active){
        props.onInterval();
        setTimeout(intervalCall, props.milliseconds);
     }
}
, [increments, props.active])
 return '';

}

用于:

return <div><IntervalRunner onInterval={loopingFunction} milliseconds="5000" active={activeVar} /></div>

【讨论】:

    猜你喜欢
    • 2020-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-21
    • 1970-01-01
    • 2011-09-30
    • 1970-01-01
    相关资源
    最近更新 更多