Javascript setInterval 未检测到全局变量更改 (React Native)

Javascript setInterval not detecting global variable change (React Native)

我正在开发一个用于与 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 作为计时器调用的函数却不会吗?

看来这是一个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. 清除并re-create每个组件渲染的间隔
  2. 使用 useRef 存储值,以便第一次渲染的 readStatus 始终引用 up-to-date 值

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

   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 '';
     
}

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

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>